├── src ├── main │ ├── resources │ │ └── view │ │ │ ├── graphics │ │ │ ├── types.js │ │ │ ├── gameConstants.js │ │ │ ├── utils.js │ │ │ ├── hex.js │ │ │ ├── TooltipManager.js │ │ │ ├── Deserializer.js │ │ │ └── assetConstants.js │ │ │ ├── assets │ │ │ ├── logo.png │ │ │ ├── light.png │ │ │ ├── blue_idle.png │ │ │ ├── sleep_red.png │ │ │ ├── sprites.png │ │ │ ├── background.jpg │ │ │ ├── hynings_48.png │ │ │ ├── outer_ringA.png │ │ │ ├── outer_ringB.png │ │ │ ├── shadowDebug.png │ │ │ ├── sleep_blue.png │ │ │ ├── Fleche-Soleil.png │ │ │ ├── debout_small.png │ │ │ ├── sprites.json │ │ │ ├── sleep_red.json │ │ │ ├── sleep_blue.json │ │ │ ├── debout_small.json │ │ │ └── blue_idle.json │ │ │ └── config.js │ └── java │ │ └── com │ │ └── codingame │ │ ├── view │ │ ├── CellData.java │ │ ├── ShadowData.java │ │ ├── SeedData.java │ │ ├── TreeData.java │ │ ├── EventData.java │ │ ├── GlobalViewData.java │ │ ├── PlayerData.java │ │ ├── FrameViewData.java │ │ ├── AnimationData.java │ │ ├── ViewModule.java │ │ ├── Serializer.java │ │ └── GameDataProvider.java │ │ └── game │ │ ├── FrameType.java │ │ ├── Growth.java │ │ ├── action │ │ ├── WaitAction.java │ │ ├── GrowAction.java │ │ ├── CompleteAction.java │ │ ├── SeedAction.java │ │ └── Action.java │ │ ├── exception │ │ ├── GameException.java │ │ ├── CellNotFoundException.java │ │ ├── TreeNotFoundException.java │ │ ├── CellNotEmptyException.java │ │ ├── CellNotValidException.java │ │ ├── TreeIsSeedException.java │ │ ├── TreeNotTallException.java │ │ ├── AlreadyActivatedTree.java │ │ ├── TreeAlreadyTallException.java │ │ ├── NotEnoughSunException.java │ │ ├── TreeTooFarException.java │ │ └── NotOwnerOfTreeException.java │ │ ├── Sun.java │ │ ├── InvalidInputException.java │ │ ├── Board.java │ │ ├── Seed.java │ │ ├── Cell.java │ │ ├── Constants.java │ │ ├── Tree.java │ │ ├── Config.java │ │ ├── Player.java │ │ ├── CubeCoord.java │ │ ├── BoardGenerator.java │ │ ├── Referee.java │ │ ├── CommandManager.java │ │ └── GameSummaryManager.java └── test │ ├── java │ ├── TestMain.java │ ├── BasicAgent.java │ └── Spring2021.java │ └── resources │ └── log4j2.properties ├── config ├── config.ini ├── level2 │ ├── GrowAction.jpg │ ├── welcome_en.html │ ├── welcome_fr.html │ └── Boss.py ├── level3 │ ├── SeedAction.jpg │ ├── welcome_en.html │ └── welcome_fr.html ├── Boss.py ├── level1 │ └── Boss.py └── stub.txt ├── .gitignore ├── starterAIs ├── README.md ├── starter.hs ├── starter.kt ├── starter.go ├── starter.cpp ├── starter.js ├── starter.py ├── starter.pl ├── starter.rb ├── starter.d ├── starter.swift ├── starter.scala ├── starter.ml ├── starter.java ├── starter.dart ├── starter.ts ├── start2.scala ├── starter.vb ├── starter.cs ├── starter.rs └── starter.php ├── README.md └── pom.xml /src/main/resources/view/graphics/types.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/config.ini: -------------------------------------------------------------------------------- 1 | min_players=2 2 | max_players=2 3 | type=multi -------------------------------------------------------------------------------- /src/main/resources/view/graphics/gameConstants.js: -------------------------------------------------------------------------------- 1 | export const TODO = 0; 2 | -------------------------------------------------------------------------------- /config/level2/GrowAction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/config/level2/GrowAction.jpg -------------------------------------------------------------------------------- /config/level3/SeedAction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/config/level3/SeedAction.jpg -------------------------------------------------------------------------------- /src/main/resources/view/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/logo.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/light.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/blue_idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/blue_idle.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/sleep_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/sleep_red.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/sprites.png -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/CellData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | public class CellData { 4 | int q, r, richness, index; 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/view/assets/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/background.jpg -------------------------------------------------------------------------------- /src/main/resources/view/assets/hynings_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/hynings_48.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/outer_ringA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/outer_ringA.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/outer_ringB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/outer_ringB.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/shadowDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/shadowDebug.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/sleep_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/sleep_blue.png -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/ShadowData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | public class ShadowData { 4 | int index; 5 | int size; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/view/assets/Fleche-Soleil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/Fleche-Soleil.png -------------------------------------------------------------------------------- /src/main/resources/view/assets/debout_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodinGame/SpringChallenge2021/HEAD/src/main/resources/view/assets/debout_small.png -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/SeedData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | public class SeedData { 4 | int owner, sourceIndex, targetIndex; 5 | 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.project 3 | /.classpath 4 | /bin/ 5 | .factorypath 6 | /.settings/ 7 | statement_en.html 8 | statement_fr.html 9 | .pydevproject 10 | copy.sh -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/FrameType.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | public enum FrameType { 4 | GATHERING, 5 | ACTIONS, 6 | SUN_MOVE, 7 | INIT 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/TreeData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | public class TreeData { 4 | int index, size, owner, sunPoints; 5 | boolean isDormant; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Growth.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | public class Growth { 4 | public int targetId; 5 | public Player player; 6 | public int cost; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/EventData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | import java.util.List; 4 | 5 | public class EventData { 6 | 7 | public List animData; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/TestMain.java: -------------------------------------------------------------------------------- 1 | public class TestMain { 2 | public static void main(String[] args) { 3 | System.setProperty("league.level", "1"); 4 | System.setProperty("allow.config.override", "true"); 5 | 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/action/WaitAction.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.action; 2 | 3 | public class WaitAction extends Action { 4 | 5 | @Override 6 | public boolean isWait() { 7 | return true; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/GlobalViewData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | import java.util.List; 4 | 5 | public class GlobalViewData { 6 | 7 | public List cells; 8 | public List nutrients; 9 | public int totalRounds; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/GameException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class GameException extends Exception { 5 | 6 | public GameException(String string) { 7 | super(string); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/PlayerData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | import java.util.List; 4 | 5 | public class PlayerData { 6 | int sun, score; 7 | public List activated; 8 | public boolean isWaiting; 9 | public String message; 10 | public List affected; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/CellNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class CellNotFoundException extends GameException { 5 | 6 | public CellNotFoundException(int id) { 7 | super("Cell " + id + " not found"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/TreeNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class TreeNotFoundException extends GameException { 5 | 6 | public TreeNotFoundException(int id) { 7 | super("There is no tree on cell " + id); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/action/GrowAction.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.action; 2 | 3 | public class GrowAction extends Action { 4 | 5 | public GrowAction(int targetId) { 6 | this.targetId = targetId; 7 | } 8 | 9 | @Override 10 | public boolean isGrow() { 11 | return true; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/CellNotEmptyException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class CellNotEmptyException extends GameException { 5 | 6 | public CellNotEmptyException(int id) { 7 | super("There is already a tree on cell " + id); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/CellNotValidException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class CellNotValidException extends GameException { 5 | 6 | public CellNotValidException(int id) { 7 | super("You can't plant a seed on cell " + id); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/TreeIsSeedException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class TreeIsSeedException extends GameException { 5 | 6 | public TreeIsSeedException(int id) { 7 | super("The seed on " + id + " cannot produce seeds"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/TreeNotTallException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class TreeNotTallException extends GameException { 5 | 6 | public TreeNotTallException(int id) { 7 | super("The tree on cell " + id + " is not large enough"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/action/CompleteAction.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.action; 2 | 3 | public class CompleteAction extends Action { 4 | 5 | public CompleteAction(int targetId) { 6 | this.targetId = targetId; 7 | } 8 | 9 | @Override 10 | public boolean isComplete() { 11 | return true; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /config/level2/welcome_en.html: -------------------------------------------------------------------------------- 1 |
2 |

You've made it to the next league.

3 | You now have the ability to make trees GROW! 4 |
5 |
See the updated statement for details.
6 |
-------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/AlreadyActivatedTree.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class AlreadyActivatedTree extends GameException { 5 | 6 | public AlreadyActivatedTree(int id) { 7 | super("Tree on cell " + id + " is dormant (has already been used this round)"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/TreeAlreadyTallException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class TreeAlreadyTallException extends GameException { 5 | 6 | public TreeAlreadyTallException(int id) { 7 | super("Tree on cell " + id + " cannot grow more (max size is 3)."); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/NotEnoughSunException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class NotEnoughSunException extends GameException { 5 | 6 | public NotEnoughSunException(int cost, int sun) { 7 | super(String.format("Not enough sun. You need %d but have %d", cost, sun)); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/test/resources/log4j2.properties: -------------------------------------------------------------------------------- 1 | # Configuration 2 | name = PropertiesConfig 3 | status = WARN 4 | 5 | appender.console.type = Console 6 | appender.console.name = CONSOLE 7 | appender.console.layout.type = PatternLayout 8 | appender.console.layout.pattern = [%d{HH:mm:ss}] %-5p : %c{1} - %m%n 9 | 10 | rootLogger.level = error 11 | rootLogger.appenderRef.console.ref = CONSOLE 12 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/action/SeedAction.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.action; 2 | 3 | public class SeedAction extends Action { 4 | 5 | public SeedAction(int sourceId, int targetId) { 6 | this.sourceId = sourceId; 7 | this.targetId = targetId; 8 | } 9 | 10 | @Override 11 | public boolean isSeed() { 12 | return true; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/TreeTooFarException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class TreeTooFarException extends GameException { 5 | 6 | public TreeTooFarException(int from, int to) { 7 | super(String.format("The tree on cell %d is too far from cell %d to plant a seed there", from, to)); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /config/level2/welcome_fr.html: -------------------------------------------------------------------------------- 1 |
2 |

Vous venez d'atteindre la ligue supérieure.

3 | Vous pouvez maintenant faire pousser (GROW) vos arbres ! 4 |
5 |
Consultez l'énoncé mis à jour pour plus de détails.
6 |
-------------------------------------------------------------------------------- /starterAIs/README.md: -------------------------------------------------------------------------------- 1 | # Starter AIs 2 | 3 | These starter AIs are meant to help new players to parse the input and have a small structure to begin with. 4 | 5 | A few lines of logic on top of these should be enough to beat the first bosses. 6 | 7 | Feel free to contribute your own starter AI in another language to help other players by making a PR. We'll be happy to add your starter AI to the list. 8 | 9 | Thank you! -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/exception/NotOwnerOfTreeException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.exception; 2 | 3 | import com.codingame.game.Player; 4 | 5 | @SuppressWarnings("serial") 6 | public class NotOwnerOfTreeException extends GameException { 7 | 8 | public NotOwnerOfTreeException(int id, Player player) { 9 | super("The tree on cell " + id + " is owned by opponent"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/FrameViewData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | public class FrameViewData { 7 | 8 | public List trees; 9 | public List seeds; 10 | public List shadows; 11 | public List players; 12 | public int frameType; 13 | public int round, sunOrientation, nutrients; 14 | 15 | } -------------------------------------------------------------------------------- /src/main/resources/view/graphics/utils.js: -------------------------------------------------------------------------------- 1 | import * as utils from '../core/utils.js'; 2 | export function setAnimationProgress(fx, progress) { 3 | let idx = Math.floor(progress * fx.totalFrames); 4 | idx = Math.min(fx.totalFrames - 1, idx); 5 | fx.gotoAndStop(idx); 6 | } 7 | export function fit(entity, maxWidth, maxHeight) { 8 | entity.scale.set(utils.fitAspectRatio(entity.texture.width, entity.texture.height, maxWidth, maxHeight)); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Sun.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | public class Sun { 4 | private int orientation; 5 | 6 | public Sun() { 7 | } 8 | 9 | public int getOrientation() { 10 | return orientation; 11 | } 12 | 13 | public void setOrientation(int orientation) { 14 | this.orientation = (orientation) % 6; 15 | } 16 | 17 | public void move() { 18 | orientation = (orientation + 1) % 6; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/BasicAgent.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.io.*; 3 | import java.math.*; 4 | 5 | /** 6 | * Auto-generated code below aims at helping you parse the standard input according to the problem statement. 7 | **/ 8 | class BasicAgent { 9 | 10 | public static void main(String args[]) { 11 | Scanner in = new Scanner(System.in); 12 | 13 | // game loop 14 | while (true) { 15 | System.out.println("WAIT"); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /config/level3/welcome_en.html: -------------------------------------------------------------------------------- 1 |
2 |

You've made it to the next league.

3 | You now have the ability to plant new trees by generating a SEED! 4 |
5 | Additionally, trees now cast shadows that the sun-gathering spirits might find too spooky! 6 |
See the updated statement for details.
7 |
-------------------------------------------------------------------------------- /src/main/resources/view/graphics/hex.js: -------------------------------------------------------------------------------- 1 | import { TILE_HEIGHT } from './assetConstants.js'; 2 | const TILE_SEPERATION = 2; 3 | export const HEXAGON_HEIGHT = TILE_HEIGHT + TILE_SEPERATION; 4 | export const HEXAGON_RADIUS = HEXAGON_HEIGHT / 2; 5 | export const HEXAGON_WIDTH = HEXAGON_RADIUS * Math.sqrt(3); 6 | export const HEXAGON_Y_SEP = HEXAGON_RADIUS * 3 / 2; 7 | export function hexToScreen(q, r) { 8 | const x = HEXAGON_RADIUS * (Math.sqrt(3) * q + Math.sqrt(3) / 2 * r); 9 | const y = HEXAGON_RADIUS * 3 / 2 * r; 10 | return { x, y }; 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Challenge 2021 2 | 3 | The theme and game for this challenge are strongly inspired by **Hjalmar Hach**'s excellent board game [Photosynthesis](https://blueorangegames.eu/en/games/photosynthesis/). 4 | 5 | Source code for CodinGame's Spring Challenge 2021 event. 6 | 7 | https://www.codingame.com/contests/spring-challenge-2021/ 8 | 9 | Community starter AIs are located here: 10 | 11 | https://github.com/CodinGame/SpringChallenge2021/tree/main/starterAIs 12 | 13 | 14 | Introduction video by Gaurav Sen: 15 | 16 | https://youtu.be/gZMdOiqchDk 17 | -------------------------------------------------------------------------------- /config/level3/welcome_fr.html: -------------------------------------------------------------------------------- 1 |
2 |

Vous venez d'atteindre la ligue supérieure.

3 | Vous pouvez maintenant planter de nouveaux arbres en jetant des graines (SEED) ! 4 |
5 | De plus, vos arbres projettent des ombres que les petits esprits récolteurs de soleil peuvent trouver menaçantes ! 6 |
Consultez l'énoncé mis à jour pour plus de détails.
7 |
-------------------------------------------------------------------------------- /src/main/java/com/codingame/game/InvalidInputException.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | @SuppressWarnings("serial") 4 | public class InvalidInputException extends Exception { 5 | private final String expected; 6 | private final String got; 7 | 8 | public InvalidInputException(String expected, String got) { 9 | super("Invalid Input: Expected " + expected + " but got '" + got + "'"); 10 | this.expected = expected; 11 | this.got = got; 12 | } 13 | 14 | public String getExpected() { 15 | return expected; 16 | } 17 | 18 | public String getGot() { 19 | return got; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Board.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Map.Entry; 6 | import java.util.stream.Collectors; 7 | 8 | public class Board { 9 | 10 | public final Map map; 11 | public final List coords; 12 | 13 | public Board(Map map) { 14 | this.map = map; 15 | coords = map.entrySet() 16 | .stream() 17 | .sorted( 18 | (a, b) -> a.getValue().getIndex() - b.getValue().getIndex() 19 | ) 20 | .map(Entry::getKey) 21 | .collect(Collectors.toList()); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Seed.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | public class Seed { 4 | private int owner; 5 | private int sourceCell; 6 | private int targetCell; 7 | 8 | public int getOwner() { 9 | return owner; 10 | } 11 | 12 | public void setOwner(int owner) { 13 | this.owner = owner; 14 | } 15 | 16 | public int getSourceCell() { 17 | return sourceCell; 18 | } 19 | 20 | public void setSourceCell(int sourceCell) { 21 | this.sourceCell = sourceCell; 22 | } 23 | 24 | public int getTargetCell() { 25 | return targetCell; 26 | } 27 | 28 | public void setTargetCell(int targetCell) { 29 | this.targetCell = targetCell; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/action/Action.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game.action; 2 | 3 | public abstract class Action { 4 | public Integer sourceId; 5 | public Integer targetId; 6 | 7 | public static final Action NO_ACTION = new Action() { 8 | }; 9 | 10 | public boolean isGrow() { 11 | return false; 12 | } 13 | 14 | public boolean isComplete() { 15 | return false; 16 | } 17 | 18 | public boolean isSeed() { 19 | return false; 20 | } 21 | 22 | public boolean isWait() { 23 | return false; 24 | } 25 | 26 | public Integer getSourceId() { 27 | return sourceId; 28 | } 29 | 30 | public Integer getTargetId() { 31 | return targetId; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Cell.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | public class Cell { 4 | public static final Cell NO_CELL = new Cell(-1) { 5 | @Override 6 | public boolean isValid() { 7 | return false; 8 | } 9 | 10 | @Override 11 | public int getIndex() { 12 | return -1; 13 | } 14 | }; 15 | 16 | private int richness; 17 | private int index; 18 | 19 | public Cell(int index) { 20 | this.index = index; 21 | } 22 | 23 | public int getIndex() { 24 | return index; 25 | } 26 | 27 | public boolean isValid() { 28 | return true; 29 | } 30 | 31 | public void setRichness(int richness) { 32 | this.richness = richness; 33 | } 34 | 35 | public int getRichness() { 36 | return richness; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/AnimationData.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | public class AnimationData { 4 | public static final int SHORT = 100; 5 | public static final int QUICK = 300; 6 | public static final int LONG = 500; 7 | 8 | int start, end; 9 | Integer trigger; 10 | Integer triggerEnd; 11 | 12 | public AnimationData(int start, int duration) { 13 | this.start = start; 14 | this.end = start + duration; 15 | this.trigger = null; 16 | this.triggerEnd = null; 17 | } 18 | 19 | public AnimationData(int start, int duration, Integer triggerAfter, Integer triggerDuration) { 20 | this.start = start; 21 | this.end = start + duration; 22 | this.trigger = triggerAfter == null ? null : start + triggerAfter; 23 | this.triggerEnd = triggerDuration == null ? null : start + triggerAfter + triggerDuration; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /config/Boss.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import math 3 | import random 4 | 5 | number_of_cells = int(input()) 6 | for i in range(number_of_cells): 7 | cell_index, richness, neigh_0, neigh_1, neigh_2, neigh_3, neigh_4, neigh_5 = [int(j) for j in input().split()] 8 | 9 | random.seed('🌱') # Get it? 10 | 11 | # game loop 12 | while True: 13 | _round = int(input()) 14 | nutrients = int(input()) 15 | sun, score = [int(i) for i in input().split()] 16 | other_sun, other_score, other_is_waiting = [int(i) for i in input().split()] 17 | number_of_trees = int(input()) 18 | for i in range(number_of_trees): 19 | cell_index, size, tree_owner, is_dormant = [int(j) for j in input().split()] 20 | possible_move_number = int(input()) 21 | 22 | moves = [] 23 | for i in range(possible_move_number): 24 | raw = input() 25 | if raw != 'WAIT': 26 | moves.append(raw) 27 | 28 | if not moves: 29 | move = 'WAIT' 30 | else: 31 | move = random.choice(moves) 32 | print(move) 33 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Constants.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | public class Constants { 4 | 5 | public static final int RICHNESS_NULL = 0; 6 | public static final int RICHNESS_POOR = 1; 7 | public static final int RICHNESS_OK = 2; 8 | public static final int RICHNESS_LUSH = 3; 9 | 10 | public static final int TREE_SEED = 0; 11 | public static final int TREE_SMALL = 1; 12 | public static final int TREE_MEDIUM = 2; 13 | public static final int TREE_TALL = 3; 14 | 15 | public static final int[] TREE_BASE_COST = new int[] { 0, 1, 3, 7}; 16 | public static final int TREE_COST_SCALE = 1; 17 | public static final int LIFECYCLE_END_COST = 4; 18 | public static final int DURATION_ACTION_PHASE = 1000; 19 | public static final int DURATION_GATHER_PHASE = 2000; 20 | public static final int DURATION_SUNMOVE_PHASE = 1000; 21 | public static final int STARTING_TREE_COUNT = 2; 22 | public static final int RICHNESS_BONUS_OK = 2; 23 | public static final int RICHNESS_BONUS_LUSH = 4; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Tree.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | public class Tree { 4 | private int size; 5 | private Player owner; 6 | private int fatherIndex = -1; 7 | private boolean isDormant; 8 | 9 | public int getFatherIndex() { 10 | return fatherIndex; 11 | } 12 | 13 | public void setFatherIndex(int fatherIndex) { 14 | this.fatherIndex = fatherIndex; 15 | } 16 | 17 | public Player getOwner() { 18 | return owner; 19 | } 20 | 21 | public void setOwner(Player owner) { 22 | this.owner = owner; 23 | } 24 | 25 | public int getSize() { 26 | return size; 27 | } 28 | 29 | public void setSize(int size) { 30 | this.size = size; 31 | } 32 | 33 | public void grow() { 34 | size++; 35 | } 36 | 37 | public boolean isDormant() { 38 | return isDormant; 39 | } 40 | 41 | public void setDormant() { 42 | this.isDormant = true; 43 | } 44 | 45 | public void reset() { 46 | this.isDormant = false; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /config/level1/Boss.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import math 3 | import random 4 | 5 | def evaluate(move): 6 | instr = move 7 | is_complete = 'COMPLETE' in instr 8 | is_grow = 'GROW' in instr 9 | is_seed = 'SEED' in instr 10 | index = 999 11 | if is_complete or is_grow or is_seed: 12 | index = int(instr.split(' ')[-1]) 13 | return (is_complete, is_grow, is_seed, -index) 14 | 15 | number_of_cells = int(input()) 16 | for i in range(number_of_cells): 17 | cell_index, richness, neigh_0, neigh_1, neigh_2, neigh_3, neigh_4, neigh_5 = [int(j) for j in input().split()] 18 | 19 | # game loop 20 | while True: 21 | _round = int(input()) 22 | nutrients = int(input()) 23 | sun, score = [int(i) for i in input().split()] 24 | other_sun, other_score, other_is_waiting = [int(i) for i in input().split()] 25 | number_of_trees = int(input()) 26 | for i in range(number_of_trees): 27 | cell_index, size, tree_owner, is_dormant = [int(j) for j in input().split()] 28 | possible_move_number = int(input()) 29 | 30 | moves = [] 31 | for i in range(possible_move_number): 32 | raw = input() 33 | moves.append(raw) 34 | 35 | moves.sort(key=evaluate, reverse=True) 36 | print(moves[1%len(moves)]) 37 | -------------------------------------------------------------------------------- /config/level2/Boss.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import math 3 | import random 4 | 5 | def evaluate(move): 6 | instr = move 7 | is_complete = 'COMPLETE' in instr 8 | is_grow = 'GROW' in instr 9 | is_seed = 'SEED' in instr 10 | index = 999 11 | if is_complete or is_grow or is_seed: 12 | index = int(instr.split(' ')[-1]) 13 | return (is_complete, is_grow, is_seed, -index) 14 | 15 | number_of_cells = int(input()) 16 | for i in range(number_of_cells): 17 | cell_index, richness, neigh_0, neigh_1, neigh_2, neigh_3, neigh_4, neigh_5 = [int(j) for j in input().split()] 18 | 19 | # game loop 20 | while True: 21 | _round = int(input()) 22 | nutrients = int(input()) 23 | sun, score = [int(i) for i in input().split()] 24 | other_sun, other_score, other_is_waiting = [int(i) for i in input().split()] 25 | number_of_trees = int(input()) 26 | for i in range(number_of_trees): 27 | cell_index, size, tree_owner, is_dormant = [int(j) for j in input().split()] 28 | possible_move_number = int(input()) 29 | 30 | moves = [] 31 | for i in range(possible_move_number): 32 | raw = input() 33 | moves.append(raw) 34 | 35 | moves.sort(key=evaluate, reverse=True) 36 | 37 | if 'COMPLETE' in moves[0] and score == 0: 38 | print(moves[0]) 39 | else: 40 | print(moves[1%len(moves)]) 41 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.codingame.game 7 | spring-2021 8 | 1.0-SNAPSHOT 9 | 10 | 11 | 4.0.2 12 | 1.8 13 | 1.8 14 | 15 | 16 | 17 | 18 | com.codingame.gameengine 19 | core 20 | ${gamengine.version} 21 | 22 | 23 | 24 | com.codingame.gameengine 25 | runner 26 | ${gamengine.version} 27 | 28 | 29 | 30 | com.codingame.gameengine 31 | module-toggle 32 | ${gamengine.version} 33 | 34 | 35 | 36 | com.codingame.gameengine 37 | module-endscreen 38 | ${gamengine.version} 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /config/stub.txt: -------------------------------------------------------------------------------- 1 | read numberOfCells:int 2 | loop numberOfCells read index:int richness:int neigh0:int neigh1:int neigh2:int neigh3:int neigh4:int neigh5:int 3 | 4 | gameloop 5 | 6 | read day:int 7 | read nutrients:int 8 | read sun:int score:int 9 | read oppSun:int oppScore:int oppIsWaiting:bool 10 | 11 | read numberOfTrees:int 12 | loop numberOfTrees read cellIndex:int size:int isMine:bool isDormant:bool 13 | 14 | read numberOfPossibleActions:int 15 | loop numberOfPossibleActions read possibleAction:string(31) 16 | 17 | write WAIT 18 | 19 | INPUT 20 | numberOfCells: 37 21 | index: 0 is the center cell, the next cells spiral outwards 22 | richness: 0 if the cell is unusable, 1-3 for usable cells 23 | neigh0: the index of the neighbouring cell for each direction 24 | day: the game lasts 24 days: 0-23 25 | nutrients: the base score you gain from the next COMPLETE action 26 | sun: your sun points 27 | score: your current score 28 | oppSun: opponent's sun points 29 | oppScore: opponent's score 30 | oppIsWaiting: whether your opponent is asleep until the next day 31 | numberOfTrees: the current amount of trees 32 | cellIndex: location of this tree 33 | size: size of this tree: 0-3 34 | isMine: 1 if this is your tree 35 | isDormant: 1 if this tree is dormant 36 | numberOfPossibleActions: all legal actions 37 | possibleAction: try printing something from here to start with 38 | 39 | OUTPUT 40 | GROW cellIdx | SEED sourceIdx targetIdx | COMPLETE cellIdx | WAIT 41 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/ViewModule.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | import com.codingame.gameengine.core.AbstractPlayer; 4 | import com.codingame.gameengine.core.GameManager; 5 | import com.codingame.gameengine.core.Module; 6 | import com.google.inject.Inject; 7 | import com.google.inject.Singleton; 8 | 9 | @Singleton 10 | public class ViewModule implements Module { 11 | 12 | private GameManager gameManager; 13 | private GameDataProvider gameDataProvider; 14 | 15 | @Inject 16 | ViewModule(GameManager gameManager, GameDataProvider gameDataProvider) { 17 | this.gameManager = gameManager; 18 | this.gameDataProvider = gameDataProvider; 19 | gameManager.registerModule(this); 20 | } 21 | 22 | @Override 23 | public final void onGameInit() { 24 | sendGlobalData(); 25 | sendFrameData(); 26 | } 27 | 28 | private void sendFrameData() { 29 | FrameViewData data = gameDataProvider.getCurrentFrameData(); 30 | gameManager.setViewData("graphics", Serializer.serialize(data)); 31 | } 32 | 33 | private void sendGlobalData() { 34 | GlobalViewData data = gameDataProvider.getGlobalData(); 35 | gameManager.setViewGlobalData("graphics", Serializer.serialize(data)); 36 | 37 | } 38 | 39 | @Override 40 | public final void onAfterGameTurn() { 41 | sendFrameData(); 42 | } 43 | 44 | @Override 45 | public final void onAfterOnEnd() { 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/Spring2021.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.io.IOException; 3 | import java.util.Properties; 4 | 5 | import com.codingame.gameengine.runner.MultiplayerGameRunner; 6 | 7 | public class Spring2021 { 8 | 9 | static String[] DEFAULT_AI = new String[] { 10 | "python3", "config/Boss.py" 11 | }; 12 | static String[] BOSS_WOOD2 = new String[] { 13 | "python3", "config/level1/Boss.py" 14 | }; 15 | static String[] BOSS_WOOD1 = new String[] { 16 | "python3", "config/level2/Boss.py" 17 | }; 18 | 19 | public static void main(String[] args) throws IOException, InterruptedException { 20 | launchGame(); 21 | } 22 | 23 | public static void launchGame() throws IOException, InterruptedException { 24 | 25 | MultiplayerGameRunner gameRunner = new MultiplayerGameRunner(); 26 | gameRunner.setLeagueLevel(3); 27 | Properties gameParameters = new Properties(); 28 | gameRunner.setGameParameters(gameParameters); 29 | 30 | gameRunner.addAgent( 31 | DEFAULT_AI, 32 | "Tororo", 33 | "https://static.codingame.com/servlet/fileservlet?id=61910307869345" 34 | ); 35 | 36 | gameRunner.addAgent( 37 | DEFAULT_AI, 38 | "Ghilbib", 39 | "https://static.codingame.com/servlet/fileservlet?id=61910289640958" 40 | ); 41 | 42 | gameRunner.setSeed(7308340236785320085L); 43 | 44 | gameRunner.start(8888); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Config.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | import java.util.Properties; 4 | import java.util.function.Function; 5 | 6 | public class Config { 7 | 8 | public static int STARTING_SUN = 0; 9 | public static int MAP_RING_COUNT = 3; 10 | public static int STARTING_NUTRIENTS = 20; 11 | public static int MAX_ROUNDS = 24; 12 | public static int MAX_EMPTY_CELLS = 10; 13 | 14 | public static void load(Properties params) { 15 | STARTING_SUN = getFromParams(params, "STARTING_SUN", STARTING_SUN); 16 | MAP_RING_COUNT = getFromParams(params, "MAP_RING_COUNT", MAP_RING_COUNT); 17 | STARTING_NUTRIENTS = getFromParams(params, "STARTING_NUTRIENTS_LUSH", STARTING_NUTRIENTS); 18 | MAX_ROUNDS = getFromParams(params, "MAX_ROUNDS", MAX_ROUNDS); 19 | MAX_EMPTY_CELLS = getFromParams(params, "MAX_EMPTY_CELLS", MAX_EMPTY_CELLS); 20 | } 21 | 22 | public static void export(Properties params) { 23 | } 24 | 25 | private static int getFromParams(Properties params, String name, int defaultValue) { 26 | return getFromParams(params, name, defaultValue, Integer::valueOf); 27 | } 28 | 29 | private static T getFromParams(Properties params, String name, T defaultValue, Function convert) { 30 | String inputValue = params.getProperty(name); 31 | if (inputValue != null) { 32 | try { 33 | return convert.apply(inputValue); 34 | } catch (NumberFormatException e) { 35 | // Do naught 36 | } 37 | } 38 | return defaultValue; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/resources/view/config.js: -------------------------------------------------------------------------------- 1 | import { ViewModule, api } from './graphics/ViewModule.js' 2 | import { EndScreenModule } from './endscreen-module/EndScreenModule.js' 3 | 4 | export const modules = [ 5 | ViewModule, 6 | EndScreenModule 7 | ] 8 | 9 | export const playerColors = [ 10 | '#ff1d5c', // radical red 11 | '#22a1e4', // curious blue 12 | '#ff8f16', // west side orange 13 | '#de6ddf', // lavender pink 14 | '#6ac371', // mantis green 15 | '#9975e2', // medium purple 16 | '#3ac5ca', // scooter blue 17 | '#ff0000' // solid red 18 | ] 19 | export const gameName = 'Spring2021' 20 | 21 | export const stepByStepAnimateSpeed = 3 22 | 23 | export const options = [ 24 | { 25 | title: 'DEBUG MODE', 26 | get: function () { 27 | return api.options.debugMode2 28 | }, 29 | set: function (value) { 30 | api.options.debugMode2 = value 31 | api.setDebug() 32 | }, 33 | values: { 34 | 'ON': true, 35 | 'OFF': false 36 | }, 37 | default: false 38 | },{ 39 | title: 'MESSAGES', 40 | get: function () { 41 | return api.options.messages 42 | }, 43 | set: function (value) { 44 | api.options.messages = value 45 | api.setMessage() 46 | }, 47 | values: { 48 | 'NONE': 0, 49 | 'ME': 1, 50 | 'ALL': 2 51 | }, 52 | default: 2 53 | },{ 54 | title: 'SPECIAL FX', 55 | get: function () { 56 | return api.options.showSFX 57 | }, 58 | set: function (value) { 59 | api.options.showSFX = value 60 | }, 61 | values: { 62 | 'ON': true, 63 | 'OFF': false 64 | }, 65 | default: true 66 | } 67 | ] 68 | -------------------------------------------------------------------------------- /starterAIs/starter.hs: -------------------------------------------------------------------------------- 1 | import System.IO 2 | import Control.Monad 3 | import Debug.Trace 4 | 5 | main :: IO () 6 | main = do 7 | hSetBuffering stdout NoBuffering -- DO NOT REMOVE 8 | soil <- readLn >>= flip replicateM (parseCell <$> readInts) :: IO Soil 9 | gameLoop soil 10 | 11 | gameLoop :: Soil -> IO () 12 | gameLoop soil = do 13 | day <- readLn :: IO Int -- the game lasts 24 days: 0-23 14 | nutrients <- readLn :: IO Int -- the base score you gain from the next COMPLETE action 15 | [sun,score] <- readInts 16 | [oppsun,oppscore,oppiswaiting] <- readInts 17 | 18 | trees <- readLn >>= flip replicateM (parseTree <$> readInts) :: IO [Tree] 19 | 20 | possibleMoves <- readLn >>= flip replicateM (parseMove <$> getLine) :: IO [Command] 21 | -- hPutStrLn stderr $ show possibleMoves 22 | 23 | putStrLn $ show WAIT 24 | gameLoop soil 25 | 26 | 27 | -- TYPES & INPUT PARSING 28 | 29 | readInts :: IO [Int] 30 | readInts = map read . words <$> getLine 31 | 32 | data Cell = Cell 33 | { cellIndex :: Int 34 | , cellRichness :: Int 35 | , neighbours :: [Int] 36 | } deriving (Show, Eq) 37 | 38 | type Soil = [Cell] 39 | 40 | parseCell :: [Int] -> Cell 41 | parseCell [a,b,c,d,e,f,g,h] = Cell a b [c,d,e,f,g,h] 42 | 43 | 44 | data Tree = Tree 45 | { treeIndex :: Int 46 | , treeSize :: Int 47 | , treeIsMine :: Bool 48 | , treeIsDormant :: Bool 49 | } deriving (Show, Eq) 50 | 51 | parseTree :: [Int] -> Tree 52 | parseTree [a,b,c,d] = Tree a b (c==1) (d==1) 53 | 54 | 55 | data Command = GROW Int | SEED Int Int | COMPLETE Int | WAIT deriving (Show) 56 | 57 | parseMove :: String -> Command 58 | parseMove move = 59 | case words move of 60 | ["WAIT"] -> WAIT 61 | ["GROW", i] -> GROW (read i) 62 | ["COMPLETE", i] -> COMPLETE (read i) 63 | ["SEED", i1, i2] -> SEED (read i1) (read i2) 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Player.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | import com.codingame.game.action.Action; 4 | import com.codingame.gameengine.core.AbstractMultiplayerPlayer; 5 | 6 | public class Player extends AbstractMultiplayerPlayer { 7 | private String message; 8 | private Action action; 9 | private int sun; 10 | private boolean waiting = false; 11 | private int bonusScore = 0; 12 | 13 | public Player() { 14 | sun = Config.STARTING_SUN; 15 | action = Action.NO_ACTION; 16 | 17 | } 18 | 19 | @Override 20 | public int getExpectedOutputLines() { 21 | return 1; 22 | } 23 | 24 | public void addScore(int score) { 25 | setScore(getScore() + score); 26 | } 27 | 28 | public void reset() { 29 | message = null; 30 | action = Action.NO_ACTION; 31 | } 32 | 33 | public String getMessage() { 34 | return message; 35 | } 36 | 37 | public void setMessage(String message) { 38 | this.message = message; 39 | } 40 | 41 | public void setAction(Action action) { 42 | this.action = action; 43 | } 44 | 45 | public Action getAction() { 46 | return action; 47 | } 48 | 49 | public int getSun() { 50 | return sun; 51 | } 52 | 53 | public void setSun(int sun) { 54 | this.sun = sun; 55 | } 56 | 57 | public void addSun(int sun) { 58 | this.sun += sun; 59 | } 60 | 61 | public void removeSun(int amount) { 62 | this.sun = Math.max(0, this.sun - amount); 63 | } 64 | 65 | public boolean isWaiting() { 66 | return waiting; 67 | } 68 | 69 | public void setWaiting(boolean waiting) { 70 | this.waiting = waiting; 71 | } 72 | 73 | public String getBonusScore() { 74 | if (bonusScore > 0) { 75 | return String.format( 76 | "%d points and %d trees", 77 | getScore() - bonusScore, 78 | bonusScore 79 | ); 80 | } else { 81 | return ""; 82 | } 83 | } 84 | 85 | public void addBonusScore(int bonusScore) { 86 | this.bonusScore += bonusScore; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/CubeCoord.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | import com.codingame.view.Serializer; 4 | 5 | public class CubeCoord { 6 | static int[][] directions = new int[][] { { 1, -1, 0 }, { +1, 0, -1 }, { 0, +1, -1 }, { -1, +1, 0 }, { -1, 0, +1 }, { 0, -1, +1 } }; 7 | int x, y, z; 8 | 9 | public CubeCoord(int x, int y, int z) { 10 | this.x = x; 11 | this.y = y; 12 | this.z = z; 13 | } 14 | 15 | public int getX() { 16 | return x; 17 | } 18 | 19 | public int getY() { 20 | return y; 21 | } 22 | 23 | public int getZ() { 24 | return z; 25 | } 26 | 27 | @Override 28 | public int hashCode() { 29 | final int prime = 31; 30 | int result = 1; 31 | result = prime * result + x; 32 | result = prime * result + y; 33 | result = prime * result + z; 34 | return result; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object obj) { 39 | if (this == obj) 40 | return true; 41 | if (obj == null) 42 | return false; 43 | if (getClass() != obj.getClass()) 44 | return false; 45 | CubeCoord other = (CubeCoord) obj; 46 | if (x != other.x) 47 | return false; 48 | if (y != other.y) 49 | return false; 50 | if (z != other.z) 51 | return false; 52 | return true; 53 | } 54 | 55 | CubeCoord neighbor(int orientation) { 56 | return neighbor(orientation, 1); 57 | } 58 | 59 | CubeCoord neighbor(int orientation, int distance) { 60 | int nx = this.x + directions[orientation][0] * distance; 61 | int ny = this.y + directions[orientation][1] * distance; 62 | int nz = this.z + directions[orientation][2] * distance; 63 | 64 | return new CubeCoord(nx, ny, nz); 65 | } 66 | 67 | int distanceTo(CubeCoord dst) { 68 | return (Math.abs(x - dst.x) + Math.abs(y - dst.y) + Math.abs(z - dst.z)) / 2; 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return Serializer.join(x, y, z); 74 | } 75 | 76 | public CubeCoord getOpposite() { 77 | CubeCoord oppositeCoord = new CubeCoord(-this.x, -this.y, -this.z); 78 | return oppositeCoord; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/BoardGenerator.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Random; 8 | 9 | public class BoardGenerator { 10 | 11 | static Map board; 12 | static int index; 13 | 14 | public static void generateCell(CubeCoord coord, int richness) { 15 | Cell cell = new Cell(index++); 16 | cell.setRichness(richness); 17 | board.put(coord, cell); 18 | } 19 | 20 | public static Board generate(Random random) { 21 | board = new HashMap<>(); 22 | index = 0; 23 | CubeCoord centre = new CubeCoord(0, 0, 0); 24 | 25 | generateCell(centre, Constants.RICHNESS_LUSH); 26 | 27 | CubeCoord coord = centre.neighbor(0); 28 | 29 | for (int distance = 1; distance <= Config.MAP_RING_COUNT; distance++) { 30 | for (int orientation = 0; orientation < 6; orientation++) { 31 | for (int count = 0; count < distance; count++) { 32 | if (distance == Config.MAP_RING_COUNT) { 33 | generateCell(coord, Constants.RICHNESS_POOR); 34 | } else if (distance == Config.MAP_RING_COUNT - 1) { 35 | generateCell(coord, Constants.RICHNESS_OK); 36 | } else { 37 | generateCell(coord, Constants.RICHNESS_LUSH); 38 | } 39 | coord = coord.neighbor((orientation + 2) % 6); 40 | } 41 | } 42 | coord = coord.neighbor(0); 43 | } 44 | 45 | List coordList = new ArrayList<>(board.keySet()); 46 | int coordListSize = coordList.size(); 47 | int wantedEmptyCells = Game.ENABLE_HOLES ? random.nextInt(Config.MAX_EMPTY_CELLS + 1) : 0; 48 | int actualEmptyCells = 0; 49 | 50 | while (actualEmptyCells < wantedEmptyCells - 1) { 51 | int randIndex = random.nextInt(coordListSize); 52 | CubeCoord randCoord = coordList.get(randIndex); 53 | if (board.get(randCoord).getRichness() != Constants.RICHNESS_NULL) { 54 | board.get(randCoord).setRichness(Constants.RICHNESS_NULL); 55 | actualEmptyCells++; 56 | if (!randCoord.equals(randCoord.getOpposite())) { 57 | board.get(randCoord.getOpposite()).setRichness(Constants.RICHNESS_NULL); 58 | actualEmptyCells++; 59 | } 60 | } 61 | } 62 | return new Board(board); 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/resources/view/graphics/TooltipManager.js: -------------------------------------------------------------------------------- 1 | import { HEIGHT } from '../core/constants.js'; 2 | /* global PIXI */ 3 | const PADDING = 5; 4 | const CURSOR_WIDTH = 20; 5 | function generateText(text, size, color, align) { 6 | var textEl = new PIXI.Text(text, { 7 | fontSize: Math.round(size / 1.2) + 'px', 8 | fontFamily: 'Lato', 9 | fontWeight: 'bold', 10 | fill: color, 11 | lineHeight: Math.round(size / 1.2) 12 | }); 13 | if (align === 'right') { 14 | textEl.anchor.x = 1; 15 | } 16 | else if (align === 'center') { 17 | textEl.anchor.x = 0.5; 18 | } 19 | return textEl; 20 | } 21 | ; 22 | export class TooltipManager { 23 | reinit() { 24 | const container = new PIXI.Container(); 25 | const tooltip = new PIXI.Container(); 26 | const background = new PIXI.Graphics(); 27 | const label = generateText('DEFAULT', 36, 0xFFFFFF, 'left'); 28 | label.position.x = PADDING; 29 | label.position.y = PADDING; 30 | tooltip.visible = false; 31 | tooltip.addChild(background); 32 | tooltip.addChild(label); 33 | this.tooltipBackground = background; 34 | this.tooltipLabel = label; 35 | this.tooltipContainer = container; 36 | this.tooltip = tooltip; 37 | container.addChild(this.tooltip); 38 | return container; 39 | } 40 | showTooltip(text) { 41 | this.initTooltip(this.tooltip, text); 42 | } 43 | initTooltip(tooltip, text) { 44 | this.tooltipLabel.text = text; 45 | const width = this.tooltipLabel.width + PADDING * 2; 46 | const height = this.tooltipLabel.height + PADDING * 2; 47 | this.tooltipOffset = -width; 48 | this.tooltipBackground.clear(); 49 | this.tooltipBackground.beginFill(0x0, 0.8); 50 | this.tooltipBackground.drawRect(0, 0, width, height); 51 | this.tooltipBackground.endFill(); 52 | tooltip.visible = true; 53 | } 54 | moveTooltip(event) { 55 | const newPosition = event.data.getLocalPosition(this.tooltipContainer); 56 | let xOffset = this.tooltipOffset - 10; 57 | let yOffset = -20; 58 | if (newPosition.x + xOffset < 0) { 59 | xOffset = CURSOR_WIDTH; 60 | } 61 | if (newPosition.y + this.tooltip.height > HEIGHT) { 62 | yOffset = HEIGHT - newPosition.y - this.tooltip.height; 63 | } 64 | this.tooltip.position.x = newPosition.x + xOffset; 65 | this.tooltip.position.y = newPosition.y + yOffset; 66 | } 67 | hideTooltip() { 68 | this.tooltip.visible = false; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/resources/view/graphics/Deserializer.js: -------------------------------------------------------------------------------- 1 | const MAIN_SEPARATOR = '\n'; 2 | export function parseData(raw, globalData) { 3 | const input = raw.split(MAIN_SEPARATOR) 4 | .map(hardSplit); 5 | const globalInfos = input.shift().map(x => +x); 6 | const data = { 7 | round: globalInfos[0], 8 | sunOrientation: globalInfos[1], 9 | nutrients: globalInfos[2], 10 | frameType: globalInfos[3], 11 | trees: [], 12 | seeds: [], 13 | shadows: [], 14 | players: [] 15 | }; 16 | let index = +input.shift()[0]; 17 | for (let i = 1; i <= index; i++) { 18 | const tree = input.shift().map(x => +x); 19 | data.trees.push({ 20 | index: tree[0], 21 | owner: tree[1], 22 | isDormant: tree[2] === 1, 23 | size: tree[3], 24 | sunPoints: tree[4] 25 | }); 26 | } 27 | index = +input.shift()[0]; 28 | for (let i = 1; i <= index; i++) { 29 | const seed = input.shift().map(x => +x); 30 | data.seeds.push({ 31 | owner: seed[0], 32 | sourceIndex: seed[1], 33 | targetIndex: seed[2] 34 | }); 35 | } 36 | index = +input.shift()[0]; 37 | for (let i = 1; i <= index; i++) { 38 | const shadow = input.shift().map(x => +x); 39 | data.shadows.push({ 40 | index: shadow[0], 41 | size: shadow[1] 42 | }); 43 | } 44 | index = 2; 45 | for (let i = 1; i <= index; i++) { 46 | const player = input.shift().map(x => +x); 47 | const activated = input.shift().map(x => +x); 48 | const message = input.shift().join(' '); 49 | const affected = input.length ? input.shift().map(x => +x) : []; 50 | data.players.push({ 51 | score: player[0], 52 | sun: player[1], 53 | activated, 54 | isWaiting: !!player[2], 55 | message: message !== '' ? message : null, 56 | affected 57 | }); 58 | } 59 | return data; 60 | } 61 | export function parseGlobalData(raw) { 62 | const input = raw.split(MAIN_SEPARATOR).map(x => hardSplit(x).map(y => +y)); 63 | const data = { 64 | totalRounds: input.shift()[0], 65 | nutrients: input.shift(), 66 | cells: [] 67 | }; 68 | while (input.length) { 69 | const cell = input.shift(); 70 | data.cells.push({ 71 | q: cell[0], 72 | r: cell[1], 73 | richness: cell[2], 74 | index: cell[3] 75 | }); 76 | } 77 | return data; 78 | } 79 | function hardSplit(raw) { 80 | if (raw === '') { 81 | return []; 82 | } 83 | return raw.split(' '); 84 | } 85 | -------------------------------------------------------------------------------- /starterAIs/starter.kt: -------------------------------------------------------------------------------- 1 | import java.util.* 2 | import java.io.* 3 | import java.math.* 4 | 5 | sealed class Action { 6 | data class Complete(val index: Int) : Action() 7 | data class Grow(val index: Int) : Action() 8 | data class Seed(val from: Int, val to: Int) : Action() 9 | data class Wait(val say: String) : Action() 10 | 11 | // GROW cellIdx | SEED sourceIdx targetIdx | COMPLETE cellIdx | WAIT 12 | fun toOutput() = when (this) { 13 | is Action.Complete -> "COMPLETE $index" 14 | is Action.Grow -> "GROW $index" 15 | is Action.Seed -> "SEED $from $to" 16 | is Action.Wait -> "WAIT $say" 17 | } 18 | 19 | companion object { 20 | fun of(st: String): Action = st.split(" ").let { 21 | when(it[0]) { 22 | "COMPLETE" -> Complete(it[1].toInt()) 23 | "GROW" -> Grow(it[1].toInt()) 24 | "SEED" -> Seed(it[1].toInt(), it[2].toInt()) 25 | "WAIT" -> Wait("") 26 | else -> error("unknow Action $st") 27 | } 28 | } 29 | } 30 | } 31 | 32 | data class Cell(val index: Int, val richness: Int, val neigh: Array) 33 | data class Tree(val cellIndex: Int, val size: Int, val isMine: Boolean, val isDormant: Boolean) 34 | 35 | class Game(val input: Scanner) { 36 | 37 | // index 0 is the center cell, the next cells spiral outwards 38 | // richness 0 if the cell is unusable, 1-3 for usable cells 39 | val nbCells = input.nextInt() // 37 40 | val cells = List(nbCells) { 41 | Cell(input.nextInt(), input.nextInt(), Array(6) { input.nextInt() }) 42 | } 43 | 44 | var day: Int = -1 // the game lasts 24 days: 0-23 45 | var nutrients: Int = -1 // the base score you gain from the next COMPLETE action 46 | var sun: Int = -1 // your sun points 47 | var score: Int = -1 // your current score 48 | var oppSun: Int = -1 // opponent's sun points 49 | var oppScore: Int = -1 // opponent's score 50 | var oppIsWaiting: Boolean = false // whether your opponent is asleep until the next day 51 | var trees: List = emptyList() 52 | var possibleMoves: List = emptyList() 53 | 54 | fun read() { 55 | day = input.nextInt() 56 | nutrients = input.nextInt() 57 | sun = input.nextInt() 58 | score = input.nextInt() 59 | oppSun = input.nextInt() 60 | oppScore = input.nextInt() 61 | oppIsWaiting = input.nextInt() != 0 62 | val numberOfTrees = input.nextInt() 63 | trees = List(numberOfTrees) { 64 | Tree(input.nextInt(), input.nextInt(), input.nextInt() != 0, input.nextInt() != 0) 65 | } 66 | val numberOfPossibleMoves = input.nextInt() 67 | if (input.hasNextLine()) { 68 | input.nextLine() 69 | } 70 | possibleMoves = List(numberOfPossibleMoves) { Action.of(input.nextLine()) } 71 | } 72 | } 73 | 74 | 75 | fun main(args : Array) { 76 | val input = Scanner(System.`in`) 77 | val game = Game(input) 78 | 79 | // game loop 80 | while (true) { 81 | game.read() 82 | 83 | // Write an action using println() 84 | // To debug: System.err.println("Debug messages..."); 85 | 86 | println(game.possibleMoves.first().toOutput()) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /starterAIs/starter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | type Cell struct { 12 | Index int 13 | Richness int // min: 1, max: 3 14 | Neighbours []int 15 | } 16 | 17 | type Tree struct { 18 | CellId int 19 | Size int 20 | Mine bool 21 | Dormant bool 22 | } 23 | 24 | type Action struct { 25 | Type string 26 | TargetCell int 27 | SourceCell int 28 | } 29 | 30 | type Game struct { 31 | Day int 32 | Nutrients int 33 | Board []Cell 34 | PossibleActions []*Action 35 | Trees []Tree 36 | MySun int 37 | OpponentSun int 38 | MyScore int 39 | OpponentScore int 40 | OpponentIsWaiting bool 41 | } 42 | 43 | var game Game 44 | 45 | func (game *Game) move() { 46 | // Add your game code here 47 | fmt.Println("WAIT") 48 | return 49 | } 50 | 51 | func main() { 52 | scanner := bufio.NewScanner(os.Stdin) 53 | scanner.Buffer(make([]byte, 1000000), 1000000) 54 | 55 | var numberOfCells int 56 | scanner.Scan() 57 | fmt.Sscan(scanner.Text(), &numberOfCells) 58 | 59 | game.Nutrients = 20 60 | game.Board = make([]Cell, numberOfCells) 61 | 62 | for i := 0; i < numberOfCells; i++ { 63 | var index, richness, neigh0, neigh1, neigh2, neigh3, neigh4, neigh5 int 64 | scanner.Scan() 65 | fmt.Sscan(scanner.Text(), &index, &richness, &neigh0, &neigh1, &neigh2, &neigh3, &neigh4, &neigh5) 66 | 67 | game.Board[i] = Cell{ 68 | index, 69 | richness, 70 | []int{ 71 | neigh0, neigh1, neigh2, neigh3, neigh4, neigh5, 72 | }, 73 | } 74 | } 75 | for { 76 | scanner.Scan() 77 | fmt.Sscan(scanner.Text(), &game.Day) 78 | scanner.Scan() 79 | fmt.Sscan(scanner.Text(), &game.Nutrients) 80 | scanner.Scan() 81 | fmt.Sscan(scanner.Text(), &game.MySun, &game.MyScore) 82 | 83 | scanner.Scan() 84 | var _oppIsWaiting int 85 | fmt.Sscan(scanner.Text(), &game.OpponentSun, &game.OpponentScore, &_oppIsWaiting) 86 | game.OpponentIsWaiting = _oppIsWaiting != 0 87 | 88 | var numberOfTrees int 89 | scanner.Scan() 90 | fmt.Sscan(scanner.Text(), &numberOfTrees) 91 | 92 | game.Trees = make([]Tree, numberOfTrees) 93 | for i := 0; i < numberOfTrees; i++ { 94 | var cellIndex, size int 95 | var isMine, isDormant bool 96 | var _isMine, _isDormant int 97 | scanner.Scan() 98 | fmt.Sscan(scanner.Text(), &cellIndex, &size, &_isMine, &_isDormant) 99 | isMine = _isMine != 0 100 | isDormant = _isDormant != 0 101 | 102 | game.Trees[i] = Tree{cellIndex, size, isMine, isDormant} 103 | } 104 | 105 | var numberOfPossibleMoves int 106 | scanner.Scan() 107 | fmt.Sscan(scanner.Text(), &numberOfPossibleMoves) 108 | 109 | game.PossibleActions = make([]*Action, numberOfPossibleMoves) 110 | for i := 0; i < numberOfPossibleMoves; i++ { 111 | scanner.Scan() 112 | possibleMove := scanner.Text() 113 | toks := strings.Split(possibleMove, " ") 114 | action := &Action{toks[0], 0, 0} 115 | switch toks[0] { 116 | case "COMPLETE": 117 | action.TargetCell, _ = strconv.Atoi(toks[1]) 118 | case "GROW": 119 | action.TargetCell, _ = strconv.Atoi(toks[1]) 120 | case "SEED": 121 | action.SourceCell, _ = strconv.Atoi(toks[1]) 122 | action.TargetCell, _ = strconv.Atoi(toks[2]) 123 | case "WAIT": 124 | _ = "" 125 | default: 126 | panic(fmt.Sprintf("Unexpected action '%s'.", toks[0])) 127 | } 128 | game.PossibleActions[i] = action 129 | } 130 | 131 | game.move() 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/resources/view/assets/sprites.json: -------------------------------------------------------------------------------- 1 | {"frames":{"Arbre0_Blue.png":{"frame":{"x":652,"y":374,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Arbre0_Red.png":{"frame":{"x":489,"y":187,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Arbre1_Blue.png":{"frame":{"x":323,"y":526,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Arbre1_Red.png":{"frame":{"x":652,"y":561,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Arbre2_Blue.png":{"frame":{"x":652,"y":935,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Arbre2_Red.png":{"frame":{"x":652,"y":748,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Arbre3_Blue.png":{"frame":{"x":326,"y":187,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Arbre3_Red.png":{"frame":{"x":0,"y":0,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Arbre3_White.png":{"frame":{"x":326,"y":0,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"bubble.png":{"frame":{"x":0,"y":526,"w":322,"h":218},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":322,"h":218},"sourceSize":{"w":322,"h":218}},"Devant.png":{"frame":{"x":0,"y":374,"w":392,"h":151},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":392,"h":151},"sourceSize":{"w":392,"h":151}},"Dormant_Bleu.png":{"frame":{"x":0,"y":187,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Dormant_Rouge.png":{"frame":{"x":163,"y":187,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"hud.png":{"frame":{"x":0,"y":745,"w":635,"h":412},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":635,"h":412},"sourceSize":{"w":635,"h":412}},"Ombre.png":{"frame":{"x":652,"y":187,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Particule.png":{"frame":{"x":323,"y":713,"w":25,"h":27},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":25,"h":27},"sourceSize":{"w":25,"h":27}},"Sol_0.png":{"frame":{"x":489,"y":0,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Sol_1.png":{"frame":{"x":652,"y":0,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Sol_2.png":{"frame":{"x":486,"y":526,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"Sol_3.png":{"frame":{"x":163,"y":0,"w":162,"h":186},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":162,"h":186},"sourceSize":{"w":162,"h":186}},"sunPoint.png":{"frame":{"x":393,"y":374,"w":56,"h":56},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":56,"h":56},"sourceSize":{"w":56,"h":56}}},"meta":{"app":"https://www.leshylabs.com/apps/sstool/","version":"Leshy SpriteSheet Tool v0.8.4","image":"sprites.png","size":{"w":814,"h":1157},"scale":1}} -------------------------------------------------------------------------------- /starterAIs/starter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Cell { 10 | public: 11 | Cell () { 12 | neighbors.resize(6); 13 | } 14 | 15 | void input() { 16 | cin >> cell_index >> richness; 17 | for (auto& n: neighbors) { 18 | cin >> n; 19 | } 20 | } 21 | int cell_index; 22 | int richness; 23 | vector neighbors; 24 | }; 25 | 26 | class Tree { 27 | public: 28 | Tree () = default; 29 | Tree (int cell_index, int size, bool is_mine, bool is_dormant) : 30 | cell_index{cell_index}, size{size}, is_mine{is_mine}, is_dormant{is_dormant} {} 31 | void input() { 32 | cin >> cell_index >> size >> is_mine >> is_dormant; 33 | } 34 | int cell_index; 35 | int size; 36 | bool is_mine; 37 | bool is_dormant; 38 | }; 39 | 40 | class Game { 41 | private: 42 | int day = 0; 43 | int nutrients = 0; 44 | vector board; 45 | vector trees; 46 | vector> possible_actions; 47 | int mySun; 48 | int oppSun; 49 | int score; 50 | int oppScore; 51 | int oppIsWaiting; 52 | 53 | public: 54 | void inputInitData() { 55 | int numberOfCells; 56 | cin >> numberOfCells; 57 | for (int i = 0; i < numberOfCells; i++) { 58 | Cell cell; 59 | cell.input(); 60 | board.push_back(cell); 61 | } 62 | } 63 | 64 | void inputInfo() { 65 | // input game info 66 | cin >> day; 67 | cin >> nutrients; 68 | cin >> mySun >> score; 69 | cin >> oppSun >> oppScore >> oppIsWaiting; 70 | 71 | // input trees info 72 | trees.clear(); 73 | int numberOfTrees; 74 | cin >> numberOfTrees; 75 | for (int i = 0; i < numberOfTrees; i++) { 76 | Tree tree; 77 | tree.input(); 78 | trees.push_back(tree); 79 | } 80 | 81 | // input possible actions 82 | possible_actions.clear(); 83 | int numberOfPossibleMoves; 84 | cin >> numberOfPossibleMoves; 85 | for (int i = 0; i < numberOfPossibleMoves; i++) { 86 | string type; 87 | int arg1 = 0; 88 | int arg2 = 0; 89 | cin >> type; 90 | 91 | if (type == "WAIT") { 92 | possible_actions.push_back(make_tuple(type, arg1,arg2)); 93 | } else if (type == "COMPLETE") { 94 | cin >> arg1; 95 | possible_actions.push_back(make_tuple(type, arg1,arg2)); 96 | } 97 | else if (type == "GROW") { 98 | cin >> arg1; 99 | possible_actions.push_back(make_tuple(type, arg1,arg2)); 100 | } 101 | else if (type == "SEED") { 102 | cin >> arg1; 103 | cin >> arg2; 104 | possible_actions.push_back(make_tuple(type, arg1,arg2)); 105 | } 106 | } 107 | } 108 | 109 | // TODO: Please implement the algorithm in this function 110 | string compute_next_action() { 111 | string action = "WAIT"; // default 112 | 113 | return action; 114 | } 115 | }; 116 | 117 | int main() 118 | { 119 | Game game; 120 | game.inputInitData(); 121 | 122 | while (true) { 123 | game.inputInfo(); 124 | 125 | cout << game.compute_next_action() << endl; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /starterAIs/starter.js: -------------------------------------------------------------------------------- 1 | class Cell { 2 | constructor(index, richness, neighbors) { 3 | this.index = index 4 | this.richness = richness 5 | this.neighbors = neighbors 6 | } 7 | } 8 | class Tree { 9 | constructor(cellIndex, size, isMine, isDormant) { 10 | this.cellIndex = cellIndex 11 | this.size = size 12 | this.isMine = isMine 13 | this.isDormant = isDormant 14 | } 15 | } 16 | 17 | const WAIT = 'WAIT' 18 | const SEED = 'SEED' 19 | const GROW = 'GROW' 20 | const COMPLETE = 'COMPLETE' 21 | class Action { 22 | constructor(type, targetCellIdx, sourceCellIdx) { 23 | this.type = type 24 | this.targetCellIdx = targetCellIdx 25 | this.sourceCellIdx = sourceCellIdx 26 | } 27 | static parse(line) { 28 | const parts = line.split(' ') 29 | if (parts[0] === WAIT) { 30 | return new Action(WAIT) 31 | } 32 | if (parts[0] === SEED) { 33 | return new Action(SEED, parseInt(parts[2]), parseInt(parts[1])) 34 | } 35 | return new Action(parts[0], parseInt(parts[1])) 36 | } 37 | toString() { 38 | if (this.type === WAIT) { 39 | return WAIT 40 | } 41 | if (this.type === SEED) { 42 | return `${SEED} ${this.sourceCellIdx} ${this.targetCellIdx}` 43 | } 44 | return `${this.type} ${this.targetCellIdx}` 45 | } 46 | } 47 | class Game { 48 | constructor() { 49 | this.day = 0 50 | this.nutrients = 0 51 | this.cells = [] 52 | this.possibleActions = [] 53 | this.trees = [] 54 | this.mySun = 0 55 | this.myScore = 0 56 | this.opponentsSun = 0 57 | this.opponentScore = 0 58 | this.opponentIsWaiting = 0 59 | } 60 | getNextAction() { 61 | // TODO: write your algorithm here 62 | return this.possibleActions[0] 63 | } 64 | } 65 | 66 | const game = new Game() 67 | 68 | const numberOfCells = parseInt(readline()); 69 | for (let i = 0; i < numberOfCells; i++) { 70 | var inputs = readline().split(' '); 71 | const index = parseInt(inputs[0]); 72 | const richness = parseInt(inputs[1]); 73 | const neigh0 = parseInt(inputs[2]); 74 | const neigh1 = parseInt(inputs[3]); 75 | const neigh2 = parseInt(inputs[4]); 76 | const neigh3 = parseInt(inputs[5]); 77 | const neigh4 = parseInt(inputs[6]); 78 | const neigh5 = parseInt(inputs[7]); 79 | game.cells.push( 80 | new Cell(index, richness, [neigh0, neigh1, neigh2, neigh3, neigh4, neigh5]) 81 | ) 82 | } 83 | 84 | 85 | while (true) { 86 | game.day = parseInt(readline()); 87 | game.nutrients = parseInt(readline()); 88 | var inputs = readline().split(' '); 89 | game.mySun = parseInt(inputs[0]); 90 | game.myScore = parseInt(inputs[1]); 91 | var inputs = readline().split(' '); 92 | game.opponentSun = parseInt(inputs[0]); 93 | game.opponentScore = parseInt(inputs[1]); 94 | game.opponentIsWaiting = inputs[2] !== '0'; 95 | game.trees = [] 96 | const numberOfTrees = parseInt(readline()); 97 | for (let i = 0; i < numberOfTrees; i++) { 98 | var inputs = readline().split(' '); 99 | const cellIndex = parseInt(inputs[0]); 100 | const size = parseInt(inputs[1]); 101 | const isMine = inputs[2] !== '0'; 102 | const isDormant = inputs[3] !== '0'; 103 | game.trees.push( 104 | new Tree(cellIndex, size, isMine, isDormant) 105 | ) 106 | } 107 | game.possibleActions = [] 108 | const numberOfPossibleAction = parseInt(readline()); 109 | for (let i = 0; i < numberOfPossibleAction; i++) { 110 | const possibleAction = readline(); 111 | game.possibleActions.push(Action.parse(possibleAction)) 112 | } 113 | 114 | const action = game.getNextAction() 115 | console.log(action.toString()); 116 | } 117 | -------------------------------------------------------------------------------- /starterAIs/starter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import math 3 | from enum import Enum 4 | import random 5 | 6 | class Cell: 7 | def __init__(self, cell_index, richness, neighbors): 8 | self.cell_index = cell_index 9 | self.richness = richness 10 | self.neighbors = neighbors 11 | 12 | class Tree: 13 | def __init__(self, cell_index, size, is_mine, is_dormant): 14 | self.cell_index = cell_index 15 | self.size = size 16 | self.is_mine = is_mine 17 | self.is_dormant = is_dormant 18 | 19 | class ActionType(Enum): 20 | WAIT = "WAIT" 21 | SEED = "SEED" 22 | GROW = "GROW" 23 | COMPLETE = "COMPLETE" 24 | 25 | class Action: 26 | def __init__(self, type, target_cell_id=None, origin_cell_id=None): 27 | self.type = type 28 | self.target_cell_id = target_cell_id 29 | self.origin_cell_id = origin_cell_id 30 | 31 | def __str__(self): 32 | if self.type == ActionType.WAIT: 33 | return 'WAIT' 34 | elif self.type == ActionType.SEED: 35 | return f'SEED {self.origin_cell_id} {self.target_cell_id}' 36 | else: 37 | return f'{self.type.name} {self.target_cell_id}' 38 | 39 | @staticmethod 40 | def parse(action_string): 41 | split = action_string.split(' ') 42 | if split[0] == ActionType.WAIT.name: 43 | return Action(ActionType.WAIT) 44 | if split[0] == ActionType.SEED.name: 45 | return Action(ActionType.SEED, int(split[2]), int(split[1])) 46 | if split[0] == ActionType.GROW.name: 47 | return Action(ActionType.GROW, int(split[1])) 48 | if split[0] == ActionType.COMPLETE.name: 49 | return Action(ActionType.COMPLETE, int(split[1])) 50 | 51 | class Game: 52 | def __init__(self): 53 | self.day = 0 54 | self.nutrients = 0 55 | self.board = [] 56 | self.trees = [] 57 | self.possible_actions = [] 58 | self.my_sun = 0 59 | self.my_score = 0 60 | self.opponent_sun = 0 61 | self.opponent_score = 0 62 | self.opponent_is_waiting = 0 63 | 64 | def compute_next_action(self): 65 | return self.possible_actions[0] 66 | 67 | 68 | number_of_cells = int(input()) 69 | game = Game() 70 | for i in range(number_of_cells): 71 | cell_index, richness, neigh_0, neigh_1, neigh_2, neigh_3, neigh_4, neigh_5 = [int(j) for j in input().split()] 72 | game.board.append(Cell(cell_index, richness, [neigh_0, neigh_1, neigh_2, neigh_3, neigh_4, neigh_5])) 73 | 74 | while True: 75 | _day = int(input()) 76 | game.day = _day 77 | nutrients = int(input()) 78 | game.nutrients = nutrients 79 | sun, score = [int(i) for i in input().split()] 80 | game.my_sun = sun 81 | game.my_score = score 82 | opp_sun, opp_score, opp_is_waiting = [int(i) for i in input().split()] 83 | game.opponent_sun = opp_sun 84 | game.opponent_score = opp_score 85 | game.opponent_is_waiting = opp_is_waiting 86 | number_of_trees = int(input()) 87 | game.trees.clear() 88 | for i in range(number_of_trees): 89 | inputs = input().split() 90 | cell_index = int(inputs[0]) 91 | size = int(inputs[1]) 92 | is_mine = inputs[2] != "0" 93 | is_dormant = inputs[3] != "0" 94 | game.trees.append(Tree(cell_index, size, is_mine, is_dormant)) 95 | 96 | number_of_possible_actions = int(input()) 97 | game.possible_actions.clear() 98 | for i in range(number_of_possible_actions): 99 | possible_action = input() 100 | game.possible_actions.append(Action.parse(possible_action)) 101 | 102 | print(game.compute_next_action()) 103 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/Serializer.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | import java.util.stream.Stream; 7 | 8 | public class Serializer { 9 | 10 | static public String serialize(FrameViewData frameViewData) { 11 | List lines = new ArrayList<>(); 12 | lines.add( 13 | join( 14 | frameViewData.round, 15 | frameViewData.sunOrientation, 16 | frameViewData.nutrients, 17 | frameViewData.frameType 18 | ) 19 | ); 20 | 21 | lines.add(String.valueOf(frameViewData.trees.size())); 22 | frameViewData.trees.stream().forEach(treeData -> { 23 | lines.add( 24 | join( 25 | treeData.index, 26 | treeData.owner, 27 | treeData.isDormant ? 1 : 0, 28 | treeData.size, 29 | treeData.sunPoints 30 | ) 31 | ); 32 | }); 33 | lines.add(String.valueOf(frameViewData.seeds.size())); 34 | frameViewData.seeds.stream().forEach(seedData -> { 35 | lines.add( 36 | join( 37 | seedData.owner, 38 | seedData.sourceIndex, 39 | seedData.targetIndex 40 | ) 41 | ); 42 | }); 43 | lines.add(String.valueOf(frameViewData.shadows.size())); 44 | frameViewData.shadows.stream().forEach(shadowData -> { 45 | lines.add( 46 | join( 47 | shadowData.index, 48 | shadowData.size 49 | ) 50 | ); 51 | }); 52 | frameViewData.players.stream().forEach(playerData -> { 53 | lines.add( 54 | join( 55 | playerData.score, 56 | playerData.sun, 57 | playerData.isWaiting ? 1 : 0 58 | ) 59 | ); 60 | lines.add( 61 | playerData.activated.stream() 62 | .map(String::valueOf) 63 | .collect(Collectors.joining(" ")) 64 | ); 65 | lines.add( 66 | playerData.message == null ? "" : playerData.message 67 | ); 68 | lines.add( 69 | playerData.affected == null ? "" : playerData.affected.stream() 70 | .map(String::valueOf) 71 | .collect(Collectors.joining(" ")) 72 | ); 73 | }); 74 | return lines.stream().collect(Collectors.joining("\n")); 75 | } 76 | 77 | static public String serialize(GlobalViewData globalViewData) { 78 | List lines = new ArrayList<>(); 79 | lines.add( 80 | String.valueOf(globalViewData.totalRounds) 81 | ); 82 | lines.add( 83 | globalViewData.nutrients 84 | .stream() 85 | .map(String::valueOf) 86 | .collect(Collectors.joining(" ")) 87 | ); 88 | 89 | globalViewData.cells.stream().forEach(cellData -> { 90 | lines.add( 91 | join( 92 | cellData.q, 93 | cellData.r, 94 | cellData.richness, 95 | cellData.index 96 | ) 97 | ); 98 | }); 99 | 100 | return lines.stream().collect(Collectors.joining("\n")); 101 | } 102 | 103 | static public String join(Object... args) { 104 | return Stream.of(args) 105 | .map(String::valueOf) 106 | .collect(Collectors.joining(" ")); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /starterAIs/starter.pl: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use 5.32.1; 4 | select STDOUT; $|=1; 5 | 6 | my $game = new Game(); 7 | loadMap(); 8 | while (1) { 9 | loadTurn(); 10 | say $game->getNextAction(); 11 | } 12 | 13 | ######################## subs 14 | 15 | sub loadMap { 16 | chomp(my $number_of_cells = ); # 37 17 | 18 | for my $i (0..$number_of_cells-1) { 19 | chomp(my $tokens=); 20 | my @parms = split / /,$tokens; 21 | my $cell = new Cell(shift @parms, shift @parms, \@parms); 22 | push @{ $game->{cells} }, $cell; 23 | } 24 | } 25 | 26 | sub loadTurn { 27 | chomp($game->{day} = ); 28 | chomp($game->{nutrients} = ); 29 | 30 | chomp(my $t = ); 31 | ($game->{mySun}, $game->{myScore}) = split / /, $t; 32 | 33 | chomp($t = ); 34 | ($game->{oppSun}, $game->{oppScore}, $game->{oppIsWaiting}) = split / /, $t; 35 | 36 | chomp(my $number_of_trees = ); 37 | my @trees; 38 | for my $i (0..$number_of_trees-1) { 39 | my $tree = new Tree(); 40 | chomp($t = ); 41 | ($tree->{cellIndex}, $tree->{size}, $tree->{isMine}, $tree->{isDormant}) = split / /, $t; 42 | push @trees, $tree; 43 | } 44 | $game->{trees} = \@trees; 45 | 46 | chomp(my $number_of_actions = ); 47 | my @actions; 48 | for my $i (0..$number_of_actions-1) { 49 | chomp($t = ); 50 | my $action = Action->parse($t); 51 | push @actions, $action; 52 | } 53 | $game->{possActions} = \@actions; 54 | } 55 | 56 | ######################## classes 57 | 58 | package Game; 59 | 60 | sub new { 61 | my $type = shift; 62 | my (@cellArray, @actionArray, @treeArray); 63 | my $self = { 64 | day => 0, 65 | nutrients => 0, 66 | cells => \@cellArray, 67 | possActions => \@actionArray, 68 | trees => \@treeArray, 69 | mySun => 0, 70 | myScore => 0, 71 | oppSun => 0, 72 | oppScore => 0, 73 | oppIsWaiting => 0 74 | }; 75 | return bless $self, $type; 76 | } 77 | 78 | sub getNextAction { 79 | my $self = shift; 80 | 81 | #Your logic to determine the next action goes here. 82 | 83 | return $self->{possActions}[0]->getAction(); 84 | } 85 | 86 | package Cell; 87 | 88 | sub new { 89 | my $type = shift; 90 | my $self = { 91 | index => shift, 92 | richness => shift, 93 | neighbors => shift 94 | }; 95 | return bless $self, $type; 96 | } 97 | 98 | package Tree; 99 | 100 | sub new { 101 | my $type = shift; 102 | my $self = { 103 | cellIndex => shift, 104 | size => shift, 105 | isMine => shift, 106 | isDormant => shift 107 | }; 108 | return bless $self, $type; 109 | } 110 | 111 | package Action; 112 | 113 | use constant COMPLETE => "COMPLETE"; 114 | use constant GROW => "GROW"; 115 | use constant SEED => "SEED"; 116 | use constant WAIT => "WAIT"; 117 | 118 | sub new { 119 | my $type = shift; 120 | my $self = { 121 | type => shift, 122 | target => shift, 123 | source => shift 124 | }; 125 | return bless $self, $type; 126 | } 127 | 128 | sub parse { 129 | my ($self, $line) = @_; 130 | my @parts = split / /, $line; 131 | 132 | if ($parts[0] eq WAIT) { 133 | return new Action(WAIT); 134 | } 135 | 136 | if ($parts[0] eq SEED) { 137 | return new Action(SEED, $parts[2], $parts[1]); 138 | } 139 | 140 | return new Action($parts[0], $parts[1]); 141 | } 142 | 143 | sub getAction { 144 | my ($self) = @_; 145 | 146 | if ($self->{type} eq WAIT) { 147 | return WAIT; 148 | } 149 | 150 | if ($self->{type} eq SEED) { 151 | return SEED." ".$self->{target}." ".$self->{source}; 152 | } 153 | 154 | return $self->{type}." ".$self->{target}; 155 | } 156 | 157 | 158 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/Referee.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | import com.codingame.gameengine.core.AbstractPlayer.TimeoutException; 8 | import com.codingame.gameengine.core.AbstractReferee; 9 | import com.codingame.gameengine.core.MultiplayerGameManager; 10 | import com.codingame.gameengine.module.endscreen.EndScreenModule; 11 | import com.codingame.view.ViewModule; 12 | import com.google.inject.Inject; 13 | import com.google.inject.Singleton; 14 | 15 | @Singleton 16 | public class Referee extends AbstractReferee { 17 | 18 | @Inject private MultiplayerGameManager gameManager; 19 | @Inject private CommandManager commandManager; 20 | @Inject private Game game; 21 | @Inject private EndScreenModule endScreenModule; 22 | @Inject private ViewModule viewModule; 23 | @Inject private GameSummaryManager gameSummaryManager; 24 | 25 | long seed; 26 | 27 | int maxFrames; 28 | 29 | @Override 30 | public void init() { 31 | this.seed = gameManager.getSeed(); 32 | 33 | try { 34 | Config.load(gameManager.getGameParameters()); 35 | Config.export(gameManager.getGameParameters()); 36 | gameManager.setFirstTurnMaxTime(1000); 37 | gameManager.setTurnMaxTime(100); 38 | 39 | gameManager.setFrameDuration(500); 40 | 41 | game.init(seed); 42 | sendGlobalInfo(); 43 | 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | System.err.println("Referee failed to initialize"); 47 | abort(); 48 | } 49 | } 50 | 51 | private void abort() { 52 | System.err.println("Unexpected game end"); 53 | gameManager.endGame(); 54 | } 55 | 56 | private void sendGlobalInfo() { 57 | for (Player player : gameManager.getActivePlayers()) { 58 | for (String line : game.getGlobalInfoFor(player)) { 59 | player.sendInputLine(line); 60 | } 61 | } 62 | } 63 | 64 | @Override 65 | public void gameTurn(int turn) { 66 | game.resetGameTurnData(); 67 | 68 | if (game.getCurrentFrameType() == FrameType.ACTIONS) { 69 | // Give input to players 70 | for (Player player : gameManager.getActivePlayers()) { 71 | if (!player.isWaiting()) { 72 | for (String line : game.getCurrentFrameInfoFor(player)) { 73 | player.sendInputLine(line); 74 | } 75 | player.execute(); 76 | } 77 | } 78 | // Get output from players 79 | handlePlayerCommands(); 80 | } 81 | 82 | game.performGameUpdate(); 83 | } 84 | 85 | private void handlePlayerCommands() { 86 | for (Player player : gameManager.getActivePlayers()) { 87 | if (!player.isWaiting()) { 88 | try { 89 | commandManager.parseCommands(player, player.getOutputs(), game); 90 | } catch (TimeoutException e) { 91 | commandManager.deactivatePlayer(player, "Timeout!"); 92 | gameSummaryManager.addPlayerTimeout(player); 93 | gameSummaryManager.addPlayerDisqualified(player); 94 | } 95 | } 96 | } 97 | 98 | } 99 | 100 | @Override 101 | public void onEnd() { 102 | endScreenModule.setTitleRankingsSprite("logo.png"); 103 | 104 | game.onEnd(); 105 | 106 | int scores[] = gameManager.getPlayers().stream() 107 | .mapToInt(Player::getScore) 108 | .toArray(); 109 | 110 | String displayedText[] = gameManager.getPlayers().stream() 111 | .map(Player::getBonusScore) 112 | .toArray(String[]::new); 113 | 114 | endScreenModule.setScores(scores, displayedText); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /starterAIs/starter.rb: -------------------------------------------------------------------------------- 1 | class Cell 2 | def initialize(index, richness, neighbors) 3 | @index = index 4 | @richness = richness 5 | @neighbors = neighbors 6 | end 7 | end 8 | 9 | class Tree 10 | def initialize(cell_index, size, is_mine, is_dormant) 11 | @cell_index = cell_index 12 | @size = size 13 | @is_mine = is_mine 14 | @is_dormant = is_dormant 15 | end 16 | end 17 | 18 | WAIT = 'WAIT' 19 | SEED = 'SEED' 20 | GROW = 'GROW' 21 | COMPLETE = 'COMPLETE' 22 | 23 | class Action 24 | def self.parse(line) 25 | parts = line.split ' ' 26 | if (parts[0] == WAIT) 27 | return Action.new(WAIT) 28 | end 29 | if (parts[0] == SEED) 30 | return Action.new(SEED, parts[2].to_i, parts[1].to_i) 31 | end 32 | return Action.new(parts[0], parts[1].to_i) 33 | end 34 | 35 | def initialize(type, target_cell_idx = 0, source_cell_idx = 0) 36 | @type = type 37 | @target_cell_idx = target_cell_idx 38 | @source_cell_idx = source_cell_idx 39 | end 40 | 41 | def to_s 42 | return WAIT if @type == WAIT 43 | return "#{SEED} #{@source_cell_idx} #{@target_cell_idx}" if @type == SEED 44 | "#{@type} #{@target_cell_idx}" 45 | end 46 | end 47 | 48 | class Game 49 | attr_accessor :day, 50 | :nutrients, 51 | :cells, 52 | :possible_actions, 53 | :trees, 54 | :my_sun, 55 | :my_score, 56 | :opponent_sun, 57 | :opponent_score, 58 | :opponent_is_waiting 59 | 60 | def initialize 61 | @day = 0 62 | @nutrients = 0 63 | @cells = [] 64 | @possible_actions = [] 65 | @trees = [] 66 | @my_sun = 0 67 | @my_score = 0 68 | @opponent_sun = 0 69 | @opponent_score = 0 70 | @opponent_is_waiting = 0 71 | end 72 | 73 | def get_next_action 74 | # TODO: write your algorithm here 75 | return @possible_actions[0] 76 | end 77 | end 78 | 79 | game = Game.new 80 | 81 | STDOUT.sync = true # DO NOT REMOVE 82 | ## the standard input according to the problem statement. 83 | 84 | number_of_cells = gets.to_i # 37 85 | number_of_cells.times do 86 | # index: 0 is the center cell, the next cells spiral outwards 87 | # richness: 0 if the cell is unusable, 1-3 for usable cells 88 | # neigh_0: the index of the neighbouring cell for each direction 89 | index, richness, neigh_0, neigh_1, neigh_2, neigh_3, neigh_4, neigh_5 = gets.split(' ').collect { |x| x.to_i } 90 | game.cells << Cell.new(index, richness, [neigh_0, neigh_1, neigh_2, neigh_3, neigh_4, neigh_5]) 91 | end 92 | 93 | # game loop 94 | loop do 95 | game.day = gets.to_i # the game lasts 24 days: 0-23 96 | game.nutrients = gets.to_i # the base score you gain from the next COMPLETE action 97 | 98 | # my_sun: your sun points 99 | # my_score: your current score 100 | game.my_sun, game.my_score = gets.split(' ').collect { |x| x.to_i } 101 | 102 | # opponent_sun: opponent's sun points 103 | # opponent_score: opponent's score 104 | # opponent_is_waiting: whether your opponent is asleep until the next day 105 | inputs = gets.split(' ') 106 | game.opponent_sun = inputs[0].to_i 107 | game.opponent_score = inputs[1].to_i 108 | game.opponent_is_waiting = inputs[2] != '0' 109 | 110 | game.trees = [] 111 | number_of_trees = gets.to_i # the current amount of trees 112 | number_of_trees.times do 113 | # cell_index: location of this tree 114 | # size: size of this tree: 0-3 115 | # is_mine: 1 if this is your tree 116 | # is_dormant: 1 if this tree is dormant 117 | cell_index, size, is_mine, is_dormant = gets.split ' ' 118 | cell_index = cell_index.to_i 119 | size = size.to_i 120 | is_mine = is_mine.to_i == 1 121 | is_dormant = is_dormant.to_i == 1 122 | game.trees << Tree.new(cell_index, size, is_mine, is_dormant) 123 | end 124 | 125 | game.possible_actions = [] 126 | number_of_possible_actions = gets.to_i 127 | number_of_possible_actions.times do 128 | possible_action = gets.chomp 129 | game.possible_actions << Action.parse(possible_action) 130 | end 131 | 132 | action = game.get_next_action 133 | 134 | puts action.to_s 135 | end 136 | -------------------------------------------------------------------------------- /starterAIs/starter.d: -------------------------------------------------------------------------------- 1 | import std; 2 | package: // to avoid 'undocumented public symbol' warnings 3 | 4 | void main() { 5 | Game game; 6 | game.initalize(); 7 | game.readInput(); 8 | while (1) { 9 | game.tick(); 10 | game.readInput(); 11 | } 12 | } 13 | 14 | struct Cell { 15 | /// 0 is the center cell, the next cells spiral outwards 16 | int index; 17 | /// 0 if the cell is unusable, 1-3 for usable cells 18 | int richness; 19 | /// the index of the neighbouring cell for each direction 20 | int[6] neighbours; 21 | this(string line) { 22 | auto inputs = line.split; 23 | this.index = inputs[0].to!int; 24 | this.richness = inputs[1].to!int; 25 | this.neighbours[0..6] = inputs[2..8].map!(to!int).array; 26 | } 27 | } 28 | 29 | struct Player { 30 | int sunPoints; 31 | int score; 32 | } 33 | 34 | struct Tree { 35 | int cellIndex; /// location of this tree 36 | int size; /// size of this tree: 0-3 37 | bool isMine; /// whether this is your tree 38 | bool isDormant; 39 | 40 | this(string line) { 41 | auto s = line.split; 42 | this.cellIndex = s[0].to!int; 43 | this.size = s[1].to!int; 44 | this.isMine = s[2].to!int == 1; 45 | this.isDormant = s[3].to!int == 1; 46 | } 47 | } 48 | 49 | struct Action { 50 | enum Type { 51 | WAIT, 52 | GROW, 53 | COMPLETE, 54 | SEED, 55 | } 56 | Type type; 57 | int cellTarget; // used by GROW, COMPLETE, SEED 58 | int cellSource; // used by SEED only 59 | 60 | this(string line) { 61 | auto s = line.split; 62 | this.type = s[0].to!Type; 63 | final switch (this.type) { 64 | case Type.WAIT: 65 | break; 66 | case Type.COMPLETE: 67 | case Type.GROW: 68 | this.cellTarget = s[1].to!int; 69 | break; 70 | case Type.SEED: 71 | this.cellTarget = s[2].to!int; 72 | this.cellSource = s[1].to!int; 73 | break; 74 | } 75 | } 76 | 77 | this(Type type, int cellTarget = 0, int cellSource = 0) { 78 | this.type = type; 79 | this.cellTarget = cellTarget; 80 | this.cellSource = cellSource; 81 | } 82 | 83 | void perform() { 84 | final switch (this.type) { 85 | case Type.WAIT: 86 | writefln("WAIT"); 87 | break; 88 | case Type.COMPLETE: 89 | case Type.GROW: 90 | writefln("%s %d", type, cellTarget); 91 | break; 92 | case Type.SEED: 93 | writefln("%s %d %d", type, cellSource, cellTarget); 94 | break; 95 | } 96 | } 97 | } 98 | 99 | struct Game { 100 | Cell[] cells; 101 | Player me; /// my score 102 | Player enemy; /// opponent's score 103 | bool opponentIsWaiting = false; /// whether your opponent is asleep until the next day 104 | int day; /// the game lasts 24 days: 0-23 105 | int nutrients; /// the base score you gain from the next COMPLETE action 106 | Tree[] trees; /// trees on the board 107 | Action[] actions; /// all legal actions 108 | 109 | void initalize() { 110 | const nCells = readln.chomp.to!int; // 37 111 | this.cells = stdin.byLineCopy.map!(x => Cell(x)).take(nCells).array; 112 | } 113 | 114 | void readInput() { 115 | this.day = readln.chomp.to!int; 116 | this.nutrients = readln.chomp.to!int; 117 | 118 | const inputs0 = readln.split; 119 | this.me = Player(inputs0[0].to!int, inputs0[1].to!int); 120 | const inputs1 = readln.split; 121 | this.enemy = Player(inputs1[0].to!int, inputs1[1].to!int); 122 | this.opponentIsWaiting = inputs1[2].to!int == 1; 123 | 124 | const nTrees = readln.chomp.to!int; // the current amount of trees 125 | this.trees = stdin.byLineCopy.map!(x => Tree(x)).take(nTrees).array; 126 | const nActions = readln.chomp.to!int; // all legal actions 127 | this.actions = stdin.byLineCopy.map!(x => Action(x)).take(nActions).array; 128 | } 129 | 130 | void tick() { 131 | // TODO: write your algorithm here 132 | actions[0].perform(); 133 | //Action(Action.Type.WAIT).perform(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /starterAIs/starter.swift: -------------------------------------------------------------------------------- 1 | import Glibc 2 | import Foundation 3 | 4 | public struct StderrOutputStream: TextOutputStream { 5 | public mutating func write(_ string: String) { fputs(string, stderr) } 6 | } 7 | public var errStream = StderrOutputStream() 8 | 9 | struct Game { 10 | let cells: [Int: Cell] 11 | 12 | init() { 13 | let numberOfCells = Int(readLine()!)! 14 | cells = (0.. Action { 100 | let input = readLine()!.split(separator: " ") 101 | switch input[0].uppercased() { 102 | case "SEED": 103 | return .SEED(sourceIndex: Int(input[1])!, targetIndex: Int(input[2])!) 104 | case "GROW": 105 | return .GROW(targetIndex: Int(input[1])!) 106 | case "COMPLETE": 107 | return .COMPLETE(targetIndex: Int(input[1])!) 108 | default: 109 | return .WAIT 110 | } 111 | } 112 | 113 | var description: String { 114 | switch self { 115 | case .WAIT: return "WAIT" 116 | case .SEED(let s, let t): return "SEED \(s) \(t)" 117 | case .GROW(let t): return "GROW \(t)" 118 | case .COMPLETE(let t): return "COMPLETE \(t)" 119 | } 120 | } 121 | } 122 | 123 | let gameInfo = Game() 124 | 125 | // game loop 126 | while true { 127 | let roundInfo = Round() 128 | 129 | //TODO: here you should compute which action to execute on which field 130 | 131 | print(Action.WAIT) 132 | } 133 | -------------------------------------------------------------------------------- /src/main/resources/view/graphics/assetConstants.js: -------------------------------------------------------------------------------- 1 | export const COST_POS = { x: 155, y: 224 }; 2 | export const COST_SEP = 91; 3 | export const SUN_DATA_LIST = [ 4 | { q: 4, r: 0, activeOrientations: [3] }, 5 | { q: 4, r: -1, activeOrientations: [3, 4] }, 6 | { q: 4, r: -2, activeOrientations: [3, 4] }, 7 | { q: 4, r: -3, activeOrientations: [3, 4] }, 8 | { q: 4, r: -4, activeOrientations: [4] }, 9 | { q: 3, r: -4, activeOrientations: [4, 5] }, 10 | { q: 2, r: -4, activeOrientations: [4, 5] }, 11 | { q: 1, r: -4, activeOrientations: [4, 5] }, 12 | { q: 0, r: -4, activeOrientations: [5] }, 13 | { q: -1, r: -3, activeOrientations: [0, 5] }, 14 | { q: -2, r: -2, activeOrientations: [0, 5] }, 15 | { q: -3, r: -1, activeOrientations: [0, 5] }, 16 | { q: -4, r: 0, activeOrientations: [0] }, 17 | { q: -4, r: 1, activeOrientations: [0, 1] }, 18 | { q: -4, r: 2, activeOrientations: [0, 1] }, 19 | { q: -4, r: 3, activeOrientations: [0, 1] }, 20 | { q: -4, r: 4, activeOrientations: [1] }, 21 | { q: -3, r: 4, activeOrientations: [1, 2] }, 22 | { q: -2, r: 4, activeOrientations: [1, 2] }, 23 | { q: -1, r: 4, activeOrientations: [1, 2] }, 24 | { q: 0, r: 4, activeOrientations: [2] }, 25 | { q: 1, r: 3, activeOrientations: [2, 3] }, 26 | { q: 2, r: 2, activeOrientations: [2, 3] }, 27 | { q: 3, r: 1, activeOrientations: [2, 3] } 28 | ]; 29 | export const TILE_HEIGHT = 186; 30 | export const IDLE_FRAMES = [ 31 | ['Debout_Red0001', 'Debout_Red0002', 'Debout_Red0003', 'Debout_Red0004', 'Debout_Red0005', 'Debout_Red0006', 'Debout_Red0007', 'Debout_Red0008', 'Debout_Red0009', 'Debout_Red0010', 'Debout_Red0011', 'Debout_Red0012', 'Debout_Red0013', 'Debout_Red0014', 'Debout_Red0015', 'Debout_Red0016', 'Debout_Red0017', 'Debout_Red0018', 'Debout_Red0019', 'Debout_Red0020', 'Debout_Red0021', 'Debout_Red0022', 'Debout_Red0023', 'Debout_Red0024', 'Debout_Red0025', 'Debout_Red0026', 'Debout_Red0027', 'Debout_Red0028', 'Debout_Red0029', 'Debout_Red0030', 'Debout_Red0031', 'Debout_Red0032', 'Debout_Red0033', 'Debout_Red0034', 'Debout_Red0035', 'Debout_Red0036', 'Debout_Red0037', 'Debout_Red0038', 'Debout_Red0039', 'Debout_Red0040', 'Debout_Red0041', 'Debout_Red0042', 'Debout_Red0043', 'Debout_Red0044', 'Debout_Red0045', 'Debout_Red0046', 'Debout_Red0047', 'Debout_Red0048', 'Debout_Red0049', 'Debout_Red0050', 'Debout_Red0051', 'Debout_Red0052'], 32 | ['Debout_Blue0001', 'Debout_Blue0002', 'Debout_Blue0003', 'Debout_Blue0004', 'Debout_Blue0005', 'Debout_Blue0006', 'Debout_Blue0007', 'Debout_Blue0008', 'Debout_Blue0009', 'Debout_Blue0010', 'Debout_Blue0011', 'Debout_Blue0012', 'Debout_Blue0013', 'Debout_Blue0014', 'Debout_Blue0015', 'Debout_Blue0016', 'Debout_Blue0017', 'Debout_Blue0018', 'Debout_Blue0019', 'Debout_Blue0020', 'Debout_Blue0021', 'Debout_Blue0022', 'Debout_Blue0023', 'Debout_Blue0024', 'Debout_Blue0025', 'Debout_Blue0026', 'Debout_Blue0027', 'Debout_Blue0028', 'Debout_Blue0029', 'Debout_Blue0030', 'Debout_Blue0031', 'Debout_Blue0032', 'Debout_Blue0033', 'Debout_Blue0034', 'Debout_Blue0035', 'Debout_Blue0036', 'Debout_Blue0037', 'Debout_Blue0038', 'Debout_Blue0039', 'Debout_Blue0040', 'Debout_Blue0041', 'Debout_Blue0042', 'Debout_Blue0043', 'Debout_Blue0044', 'Debout_Blue0045', 'Debout_Blue0046', 'Debout_Blue0047', 'Debout_Blue0048', 'Debout_Blue0049', 'Debout_Blue0050', 'Debout_Blue0051', 'Debout_Blue0052'] 33 | ]; 34 | export const SLEEP_FRAMES = [ 35 | ['Dort_Red0001', 'Dort_Red0003', 'Dort_Red0005', 'Dort_Red0007', 'Dort_Red0009', 'Dort_Red0011', 'Dort_Red0013', 'Dort_Red0015', 'Dort_Red0017', 'Dort_Red0019', 'Dort_Red0021', 'Dort_Red0023', 'Dort_Red0025', 'Dort_Red0027', 'Dort_Red0029', 'Dort_Red0031', 'Dort_Red0033', 'Dort_Red0035', 'Dort_Red0037', 'Dort_Red0039', 'Dort_Red0041', 'Dort_Red0043', 'Dort_Red0045', 'Dort_Red0047', 'Dort_Red0049', 'Dort_Red0051', 'Dort_Red0053', 'Dort_Red0055', 'Dort_Red0057', 'Dort_Red0059', 'Dort_Red0061', 'Dort_Red0063', 'Dort_Red0065', 'Dort_Red0067', 'Dort_Red0069'], 36 | ['Dort_BLUE0001', 'Dort_BLUE0003', 'Dort_BLUE0005', 'Dort_BLUE0007', 'Dort_BLUE0009', 'Dort_BLUE0011', 'Dort_BLUE0013', 'Dort_BLUE0015', 'Dort_BLUE0017', 'Dort_BLUE0019', 'Dort_BLUE0021', 'Dort_BLUE0023', 'Dort_BLUE0025', 'Dort_BLUE0027', 'Dort_BLUE0029', 'Dort_BLUE0031', 'Dort_BLUE0033', 'Dort_BLUE0035', 'Dort_BLUE0037', 'Dort_BLUE0039', 'Dort_BLUE0041', 'Dort_BLUE0043', 'Dort_BLUE0045', 'Dort_BLUE0047', 'Dort_BLUE0049', 'Dort_BLUE0051', 'Dort_BLUE0053', 'Dort_BLUE0055', 'Dort_BLUE0057', 'Dort_BLUE0059', 'Dort_BLUE0061', 'Dort_BLUE0063', 'Dort_BLUE0065', 'Dort_BLUE0067', 'Dort_BLUE0069'] 37 | ]; 38 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/CommandManager.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | import java.util.List; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | import com.codingame.game.action.CompleteAction; 8 | import com.codingame.game.action.GrowAction; 9 | import com.codingame.game.action.SeedAction; 10 | import com.codingame.game.action.WaitAction; 11 | import com.google.inject.Inject; 12 | import com.google.inject.Singleton; 13 | 14 | @Singleton 15 | public class CommandManager { 16 | @Inject private GameSummaryManager gameSummaryManager; 17 | 18 | static final Pattern PLAYER_WAIT_PATTERN = Pattern.compile( 19 | "^WAIT(?:\\s+(?.*))?" 20 | ); 21 | 22 | static final Pattern PLAYER_SEED_PATTERN = Pattern.compile( 23 | "^SEED (?\\d+) (?\\d+)(?:\\s+(?.*))?" 24 | ); 25 | static final Pattern PLAYER_GROW_PATTERN = Pattern.compile( 26 | "^GROW (?\\d+)(?:\\s+(?.*))?" 27 | ); 28 | 29 | static final Pattern PLAYER_COMPLETE_PATTERN = Pattern.compile( 30 | "^COMPLETE (?\\d+)(?:\\s+(?.*))?" 31 | ); 32 | 33 | public void parseCommands(Player player, List lines, Game game) { 34 | String command = lines.get(0); 35 | 36 | if (player.isWaiting()) { 37 | return; 38 | } 39 | 40 | try { 41 | Matcher match; 42 | 43 | match = PLAYER_WAIT_PATTERN.matcher(command); 44 | if (match.matches()) { 45 | player.setAction(new WaitAction()); 46 | matchMessage(player, match); 47 | return; 48 | } 49 | 50 | if (Game.ENABLE_GROW) { 51 | match = PLAYER_GROW_PATTERN.matcher(command); 52 | if (match.matches()) { 53 | int targetId = Integer.parseInt(match.group("targetId")); 54 | player.setAction(new GrowAction(targetId)); 55 | matchMessage(player, match); 56 | return; 57 | } 58 | } 59 | 60 | match = PLAYER_COMPLETE_PATTERN.matcher(command); 61 | if (match.matches()) { 62 | int targetId = Integer.parseInt(match.group("targetId")); 63 | player.setAction(new CompleteAction(targetId)); 64 | matchMessage(player, match); 65 | return; 66 | } 67 | 68 | if (Game.ENABLE_SEED) { 69 | match = PLAYER_SEED_PATTERN.matcher(command); 70 | if (match.matches()) { 71 | int sourceId = Integer.parseInt(match.group("sourceId")); 72 | int targetId = Integer.parseInt(match.group("targetId")); 73 | player.setAction(new SeedAction(sourceId, targetId)); 74 | matchMessage(player, match); 75 | return; 76 | } 77 | } 78 | 79 | throw new InvalidInputException(Game.getExpected(), command); 80 | 81 | } catch (InvalidInputException e) { 82 | deactivatePlayer(player, e.getMessage()); 83 | gameSummaryManager.addPlayerBadCommand(player, e); 84 | gameSummaryManager.addPlayerDisqualified(player); 85 | } catch (Exception e) { 86 | InvalidInputException invalidInputException = new InvalidInputException(Game.getExpected(), e.toString()); 87 | deactivatePlayer(player, invalidInputException.getMessage()); 88 | gameSummaryManager.addPlayerBadCommand(player, invalidInputException); 89 | gameSummaryManager.addPlayerDisqualified(player); 90 | } 91 | } 92 | 93 | public void deactivatePlayer(Player player, String message) { 94 | player.deactivate(escapeHTMLEntities(message)); 95 | player.setScore(-1); 96 | } 97 | 98 | private String escapeHTMLEntities(String message) { 99 | return message 100 | .replace("<", "<") 101 | .replace(">", ">"); 102 | } 103 | 104 | private void matchMessage(Player player, Matcher match) { 105 | String message = match.group("message"); 106 | if (message != null) { 107 | String trimmed = message.trim(); 108 | if (trimmed.length() > 48) { 109 | trimmed = trimmed.substring(0, 46) + "..."; 110 | } 111 | player.setMessage(trimmed); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /starterAIs/starter.scala: -------------------------------------------------------------------------------- 1 | import math._ 2 | import scala.util._ 3 | import scala.io.StdIn._ 4 | import scala.collection.mutable.ArrayBuffer 5 | 6 | case class Cell(index: Int, richness: Int, neighbours: Array[Int]) 7 | 8 | case class Tree(cellIndex: Int, size: Int, isMine: Boolean, isDormant: Boolean) 9 | 10 | object Action { 11 | val WAIT = "WAIT" 12 | val SEED = "SEED" 13 | val GROW = "GROW" 14 | val COMPLETE = "COMPLETE" 15 | 16 | def parse(action: String): Action = { 17 | val parts = action.split(" ") 18 | parts(0) match { 19 | case WAIT => 20 | new Action(WAIT) 21 | case SEED => 22 | new Action(SEED, Integer.valueOf(parts(1)), Integer.valueOf(parts(2))) 23 | case _ => 24 | new Action(parts(0), Integer.valueOf(parts(1))) 25 | } 26 | } 27 | } 28 | 29 | case class Action(`type`: String, sourceCellIdx: Integer, targetCellIdx: Integer) { 30 | def this(`type`: String, targetCellIdx: Integer) { 31 | this(`type`, null, targetCellIdx) 32 | } 33 | 34 | def this(`type`: String) { 35 | this(`type`, null, null) 36 | } 37 | 38 | override def toString: String = { 39 | if (Action.WAIT.equalsIgnoreCase(`type`)) return Action.WAIT 40 | if (Action.SEED.equalsIgnoreCase(`type`)) return s"${Action.SEED} $sourceCellIdx $targetCellIdx" 41 | s"${`type`} $targetCellIdx" 42 | } 43 | } 44 | 45 | class Game() { 46 | var day = 0 47 | var nutrients = 0 48 | var board = ArrayBuffer.empty[Cell] 49 | var possibleActions = ArrayBuffer.empty[Action] 50 | var trees = ArrayBuffer.empty[Tree] 51 | var mySun, opponentSun = 0 52 | var myScore, opponentScore = 0 53 | var opponentIsWaiting = false 54 | 55 | def getNextAction(): Action = { // TODO: write your algorithm here 56 | possibleActions.head 57 | } 58 | } 59 | 60 | /** 61 | * Auto-generated code below aims at helping you parse 62 | * the standard input according to the problem statement. 63 | **/ 64 | object Player extends App { 65 | var game = new Game() 66 | 67 | val numberOfCells = readLine.toInt // 37 68 | for(i <- 0 until numberOfCells) { 69 | // index: 0 is the center cell, the next cells spiral outwards 70 | // richness: 0 if the cell is unusable, 1-3 for usable cells 71 | // neigh0: the index of the neighbouring cell for each direction 72 | val Array(index, richness, neigh0, neigh1, neigh2, neigh3, neigh4, neigh5) = (readLine split " ").map (_.toInt) 73 | val cell = Cell(index, richness, Array(neigh0, neigh1, neigh2, neigh3, neigh4, neigh5)) 74 | game.board += cell 75 | } 76 | 77 | // game loop 78 | while(true) { 79 | game.trees = ArrayBuffer.empty[Tree] 80 | game.possibleActions = ArrayBuffer.empty[Action] 81 | 82 | game.day = readLine.toInt // the game lasts 24 days: 0-23 83 | game.nutrients = readLine.toInt // the base score you gain from the next COMPLETE action 84 | // sun: your sun points 85 | // score: your current score 86 | val Array(sun, score) = (readLine split " ").map (_.toInt) 87 | game.mySun = sun 88 | game.myScore = score 89 | 90 | // oppSun: opponent's sun points 91 | // oppScore: opponent's score 92 | // oppIsWaiting: whether your opponent is asleep until the next day 93 | val Array(_oppSun, _oppScore, _oppIsWaiting) = readLine split " " 94 | val oppSun = _oppSun.toInt 95 | val oppScore = _oppScore.toInt 96 | val oppIsWaiting = _oppIsWaiting.toInt != 0 97 | game.opponentSun = oppSun 98 | game.opponentScore = oppScore 99 | game.opponentIsWaiting = oppIsWaiting 100 | 101 | val numberOfTrees = readLine.toInt // the current amount of trees 102 | for(i <- 0 until numberOfTrees) { 103 | // cellIndex: location of this tree 104 | // size: size of this tree: 0-3 105 | // isMine: 1 if this is your tree 106 | // isDormant: 1 if this tree is dormant 107 | val Array(_cellIndex, _size, _isMine, _isDormant) = readLine split " " 108 | val cellIndex = _cellIndex.toInt 109 | val size = _size.toInt 110 | val isMine = _isMine.toInt != 0 111 | val isDormant = _isDormant.toInt != 0 112 | val tree = Tree(cellIndex, size, isMine, isDormant) 113 | game.trees += tree 114 | } 115 | val numberOfPossibleActions = readLine.toInt // all legal actions 116 | for(i <- 0 until numberOfPossibleActions) { 117 | val possibleAction = readLine // try printing something from here to start with 118 | game.possibleActions += Action.parse(possibleAction) 119 | } 120 | 121 | // Write an action using println 122 | // To debug: Console.err.println("Debug messages...") 123 | 124 | // GROW cellIdx | SEED sourceIdx targetIdx | COMPLETE cellIdx | WAIT 125 | val action = game.getNextAction() 126 | println(action) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/game/GameSummaryManager.java: -------------------------------------------------------------------------------- 1 | package com.codingame.game; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | import com.codingame.gameengine.core.GameManager; 8 | import com.google.inject.Singleton; 9 | 10 | @Singleton 11 | public class GameSummaryManager { 12 | private List lines; 13 | 14 | public GameSummaryManager() { 15 | this.lines = new ArrayList<>(); 16 | } 17 | 18 | public String getSummary() { 19 | return toString(); 20 | } 21 | 22 | public void clear() { 23 | this.lines.clear(); 24 | } 25 | 26 | public void addPlayerBadCommand(Player player, InvalidInputException invalidInputException) { 27 | lines.add( 28 | GameManager.formatErrorMessage( 29 | String.format( 30 | "%s provided invalid input. Expected '%s'\nGot '%s'", 31 | player.getNicknameToken(), 32 | invalidInputException.getExpected(), 33 | invalidInputException.getGot() 34 | ) 35 | ) 36 | ); 37 | } 38 | 39 | public void addPlayerTimeout(Player player) { 40 | lines.add( 41 | GameManager.formatErrorMessage( 42 | String.format( 43 | "%s has not provided an action in time.", 44 | player.getNicknameToken() 45 | ) 46 | ) 47 | ); 48 | } 49 | 50 | public void addPlayerDisqualified(Player player) { 51 | lines.add( 52 | String.format( 53 | "%s was disqualified.", 54 | player.getNicknameToken() 55 | ) 56 | ); 57 | } 58 | 59 | public void addCutTree(Player player, Cell cell, int score) { 60 | lines.add( 61 | String.format( 62 | "%s is ending their tree life on cell %d, scoring %d points", 63 | player.getNicknameToken(), 64 | cell.getIndex(), 65 | score 66 | ) 67 | ); 68 | } 69 | 70 | public void addGrowTree(Player player, Cell cell) { 71 | lines.add( 72 | String.format( 73 | "%s is growing a tree on cell %d", 74 | player.getNicknameToken(), 75 | cell.getIndex() 76 | ) 77 | ); 78 | } 79 | 80 | public void addPlantSeed(Player player, Cell targetCell, Cell sourceCell) { 81 | lines.add( 82 | String.format( 83 | "%s is planting a seed on cell %d from cell %d", 84 | player.getNicknameToken(), 85 | targetCell.getIndex(), 86 | sourceCell.getIndex() 87 | ) 88 | ); 89 | } 90 | 91 | public void addWait(Player player) { 92 | lines.add( 93 | String.format( 94 | "%s is waiting", 95 | player.getNicknameToken() 96 | ) 97 | ); 98 | } 99 | 100 | public void addRound(int round) { 101 | lines.add( 102 | String.format( 103 | "Round %d/%d", 104 | round, 105 | Config.MAX_ROUNDS - 1 106 | ) 107 | ); 108 | } 109 | 110 | public void addError(String error) { 111 | lines.add(error); 112 | } 113 | 114 | public void addSeedConflict(Seed seed) { 115 | lines.add( 116 | String.format( 117 | "Seed conflict on cell %d", 118 | seed.getTargetCell() 119 | ) 120 | ); 121 | } 122 | 123 | @Override 124 | public String toString() { 125 | return lines.stream().collect(Collectors.joining("\n")); 126 | } 127 | 128 | public void addRoundTransition(int round) { 129 | lines.add( 130 | String.format( 131 | "Round %d ends", 132 | round 133 | ) 134 | ); 135 | if (round + 1 < Config.MAX_ROUNDS) { 136 | lines.add( 137 | String.format( 138 | "The sun is now pointing towards direction %d", 139 | (round + 1) % 6 140 | ) 141 | ); 142 | lines.add( 143 | String.format( 144 | "Round %d starts", 145 | round + 1 146 | ) 147 | ); 148 | } 149 | } 150 | 151 | public void addGather(Player player, int given) { 152 | lines.add( 153 | String.format( 154 | "%s has collected %d sun points", 155 | player.getNicknameToken(), 156 | given 157 | ) 158 | ); 159 | } 160 | } -------------------------------------------------------------------------------- /starterAIs/starter.ml: -------------------------------------------------------------------------------- 1 | (* Auto-generated code below aims at helping you parse *) 2 | (* the standard input according to the problem statement. *) 3 | 4 | 5 | (* to create a tree : 6 | let myTree = {pos=2; size=2; ismine = true; isdormant = false} *) 7 | (* you can access to any of the tree attribute with : 8 | let myTreePos = myTree.pos *) 9 | type tree = {pos : int; size : int; ismine : bool; isdormant : bool};; 10 | 11 | (* you can create an action like this : 12 | let a = GROW 2 and a2 = COMPLETE 3 and a3 = WAIT and a4 = SEED (2,3) or 13 | use the action function below *) 14 | type action = GROW of int | COMPLETE of int | WAIT | SEED of int*int ;; 15 | 16 | (* Convert an action string to an action type : 17 | let a = action "COMPLETE 3" return COMPLETE 3 *) 18 | let action s = match s.[0] with 19 | | 'W' -> WAIT 20 | | 'G' -> GROW (Scanf.sscanf s "%s %d" (fun _ b -> b)) 21 | | 'C' -> COMPLETE (Scanf.sscanf s "%s %d" (fun _ b -> b)) 22 | | 'S' -> let a,b = Scanf.sscanf s "%s %d %d" (fun _ a b -> a,b) in SEED (a,b) 23 | | _ -> failwith @@ s^" is an invalid action" 24 | 25 | 26 | (* Convert an action to a string 27 | toString (COMPLETE 3) return "COMPLETE 3" *) 28 | and toString = function (* a good exemple on how you can 29 | match actions *) 30 | | GROW t -> Printf.sprintf "GROW %d" t 31 | | COMPLETE t -> Printf.sprintf "COMPLETE %d" t 32 | | WAIT -> "WAIT" 33 | | SEED (a,b) -> Printf.sprintf "SEED %d %d" a b 34 | in 35 | 36 | let numberofcells = int_of_string (input_line stdin) in (* 37 *) 37 | 38 | (* create an array which contains all your neighbours index (-1 meaning that you don't have neighbours in this direction) *) 39 | let neighbourTable = Array.make numberofcells [||] 40 | 41 | (* create an array which will associate each cell to 42 | its richness *) 43 | and richnessTable = Array.make numberofcells 0 in 44 | (* return the neighbour array *) 45 | let getNeighbours x = neighbourTable.(x) 46 | (* return the richness of the tile *) 47 | and richness x = richnessTable.(x) in 48 | 49 | for i = 0 to numberofcells - 1 do 50 | (* index: 0 is the center cell, the next cells spiral outwards *) 51 | (* richness: 0 if the cell is unusable, 1-3 for usable cells *) 52 | (* neigh0: the index of the neighbouring cell for each direction *) 53 | let index, richness, neighbours = Scanf.sscanf (input_line stdin) " %d %d %d %d %d %d %d %d" (fun index richness neigh0 neigh1 neigh2 neigh3 neigh4 neigh5 -> (index, richness, [|neigh0; neigh1; neigh2; neigh3; neigh4; neigh5|])) in 54 | (* fill the dictionnaries *) 55 | richnessTable.(index) <- richness ; 56 | neighbourTable.(index) <- neighbours; 57 | done; 58 | 59 | 60 | (* game loop *) 61 | while true do 62 | (* create a dictionnary to store all the trees with their position as index*) 63 | let treeTable = Hashtbl.create 37 in 64 | let day = int_of_string (input_line stdin) in (* the game lasts 24 days: 0-23 *) 65 | let nutrients = int_of_string (input_line stdin) in (* the base score you gain from the next COMPLETE action *) 66 | (* sun: your sun points *) 67 | (* score: your current score *) 68 | let sun, score = Scanf.sscanf (input_line stdin) " %d %d" (fun sun score -> (sun, score)) in 69 | (* oppsun: opponent's sun points *) 70 | (* oppscore: opponent's score *) 71 | (* oppiswaiting: whether your opponent is asleep until the next day *) 72 | let oppsun, oppscore, oppiswaiting = Scanf.sscanf (input_line stdin) " %d %d %d" (fun oppsun oppscore oppiswaiting -> (oppsun, oppscore, oppiswaiting = 1)) in 73 | let numberoftrees = int_of_string (input_line stdin) in (* the current amount of trees *) 74 | for i = 0 to numberoftrees - 1 do 75 | (* cellindex: location of this tree *) 76 | (* size: size of this tree: 0-3 *) 77 | (* ismine: 1 if this is your tree *) 78 | (* isdormant: 1 if this tree is dormant *) 79 | let tree = Scanf.sscanf (input_line stdin) " %d %d %d %d" (fun cellindex size ismine isdormant -> {pos=cellindex; size=size; ismine = (ismine = 1); isdormant = (isdormant = 1)}) in 80 | (* add the tree to the dictionnary *) 81 | Hashtbl.add treeTable tree.pos tree; 82 | done; 83 | let numberofpossiblemoves = int_of_string (input_line stdin) in 84 | (* make a list of all the actions, replace the for loop in the codingame code *) 85 | let actionlist = 86 | let rec aux n = if n = numberofpossiblemoves then [] else (action (input_line stdin) :: aux (n+1)) 87 | in aux 0 in 88 | 89 | 90 | 91 | (* Write an action using print_endline *) 92 | (* To debug: prerr_endline "Debug message"; *) 93 | 94 | 95 | (* GROW cellIdx | SEED sourceIdx targetIdx | COMPLETE cellIdx | WAIT *) 96 | match actionlist with 97 | (* how to print an action *) 98 | | x :: xs -> print_endline @@ toString x 99 | | [] -> failwith "No action found (impossible in theory)" 100 | done;; 101 | -------------------------------------------------------------------------------- /src/main/java/com/codingame/view/GameDataProvider.java: -------------------------------------------------------------------------------- 1 | package com.codingame.view; 2 | 3 | import java.util.Arrays; 4 | import java.util.Objects; 5 | import java.util.stream.Collectors; 6 | import java.util.stream.Stream; 7 | 8 | import com.codingame.game.Cell; 9 | import com.codingame.game.Constants; 10 | import com.codingame.game.CubeCoord; 11 | import com.codingame.game.FrameType; 12 | import com.codingame.game.Game; 13 | import com.codingame.game.Player; 14 | import com.codingame.game.Tree; 15 | import com.codingame.gameengine.core.MultiplayerGameManager; 16 | import com.google.inject.Inject; 17 | import com.google.inject.Singleton; 18 | 19 | @Singleton 20 | public class GameDataProvider { 21 | @Inject private Game game; 22 | @Inject private MultiplayerGameManager gameManager; 23 | 24 | public FrameViewData getCurrentFrameData() { 25 | FrameViewData data = new FrameViewData(); 26 | data.trees = game.getTrees() 27 | .entrySet() 28 | .stream() 29 | .map(entry -> { 30 | int index = entry.getKey(); 31 | Tree tree = entry.getValue(); 32 | 33 | TreeData treeData = new TreeData(); 34 | treeData.index = index; 35 | treeData.owner = tree.getOwner().getIndex(); 36 | treeData.isDormant = tree.isDormant(); 37 | treeData.size = tree.getSize(); 38 | 39 | if (game.getCurrentFrameType() == FrameType.GATHERING) { 40 | int shadow = game.getShadows().getOrDefault(index, 0); 41 | treeData.sunPoints = Math.max(0, tree.getSize() - shadow); 42 | } 43 | 44 | return treeData; 45 | 46 | }) 47 | .collect(Collectors.toList()); 48 | 49 | data.seeds = game.getSentSeeds() 50 | .stream() 51 | .map(seed -> { 52 | SeedData seedData = new SeedData(); 53 | seedData.owner = seed.getOwner(); 54 | seedData.sourceIndex = seed.getSourceCell(); 55 | seedData.targetIndex = seed.getTargetCell(); 56 | return seedData; 57 | }) 58 | .collect(Collectors.toList()); 59 | 60 | data.shadows = game.getShadows() 61 | .entrySet() 62 | .stream() 63 | .map(entry -> { 64 | int index = entry.getKey(); 65 | int size = entry.getValue(); 66 | 67 | ShadowData shadowData = new ShadowData(); 68 | shadowData.index = index; 69 | shadowData.size = size; 70 | return shadowData; 71 | 72 | }) 73 | .collect(Collectors.toList()); 74 | 75 | data.players = gameManager.getPlayers() 76 | .stream() 77 | .map(player -> { 78 | 79 | PlayerData playerData = new PlayerData(); 80 | playerData.score = player.getScore(); 81 | playerData.sun = player.getSun(); 82 | playerData.activated = game.getTrees() 83 | .entrySet() 84 | .stream() 85 | .filter(entry -> entry.getValue().getOwner() == player && entry.getValue().isDormant()) 86 | .map(entry -> entry.getKey()) 87 | .collect(Collectors.toList()); 88 | playerData.isWaiting = player.isWaiting(); 89 | playerData.message = player.getMessage(); 90 | if (!player.isWaiting()) { 91 | playerData.affected = Stream.of(player.getAction().getSourceId(), player.getAction().getTargetId()) 92 | .filter(Objects::nonNull) 93 | .collect(Collectors.toList()); 94 | } 95 | return playerData; 96 | }) 97 | .collect(Collectors.toList()); 98 | 99 | data.round = game.getRound(); 100 | data.sunOrientation = game.getSun().getOrientation(); 101 | data.frameType = game.getCurrentFrameType().ordinal(); 102 | data.nutrients = game.getNutrients(); 103 | 104 | return data; 105 | } 106 | 107 | public GlobalViewData getGlobalData() { 108 | GlobalViewData data = new GlobalViewData(); 109 | data.cells = game.getBoard() 110 | .entrySet() 111 | .stream() 112 | .map(entry -> { 113 | 114 | CubeCoord coord = entry.getKey(); 115 | Cell cell = entry.getValue(); 116 | 117 | CellData cellData = new CellData(); 118 | cellData.q = coord.getX(); 119 | cellData.r = coord.getZ(); 120 | cellData.richness = cell.getRichness(); 121 | cellData.index = cell.getIndex(); 122 | return cellData; 123 | }) 124 | .collect(Collectors.toList()); 125 | 126 | data.nutrients = Arrays.asList(0, Constants.RICHNESS_BONUS_OK, Constants.RICHNESS_BONUS_LUSH); 127 | data.totalRounds = Game.MAX_ROUNDS; 128 | return data; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /starterAIs/starter.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | import java.util.Scanner; 4 | 5 | class Player { 6 | 7 | public static void main(String args[]) { 8 | Scanner in = new Scanner(System.in); 9 | 10 | Game game = new Game(); 11 | 12 | int numberOfCells = in.nextInt(); 13 | for (int i = 0; i < numberOfCells; i++) { 14 | int index = in.nextInt(); 15 | int richness = in.nextInt(); 16 | int neigh0 = in.nextInt(); 17 | int neigh1 = in.nextInt(); 18 | int neigh2 = in.nextInt(); 19 | int neigh3 = in.nextInt(); 20 | int neigh4 = in.nextInt(); 21 | int neigh5 = in.nextInt(); 22 | int[] neighs = new int[]{neigh0, neigh1, neigh2, neigh3, neigh4, neigh5}; 23 | Cell cell = new Cell(index, richness, neighs); 24 | game.board.add(cell); 25 | } 26 | 27 | while (true) { 28 | game.day = in.nextInt(); 29 | game.nutrients = in.nextInt(); 30 | game.mySun = in.nextInt(); 31 | game.myScore = in.nextInt(); 32 | game.opponentSun = in.nextInt(); 33 | game.opponentScore = in.nextInt(); 34 | game.opponentIsWaiting = in.nextInt() != 0; 35 | 36 | game.trees.clear(); 37 | int numberOfTrees = in.nextInt(); 38 | for (int i = 0; i < numberOfTrees; i++) { 39 | int cellIndex = in.nextInt(); 40 | int size = in.nextInt(); 41 | boolean isMine = in.nextInt() != 0; 42 | boolean isDormant = in.nextInt() != 0; 43 | Tree tree = new Tree(cellIndex, size, isMine, isDormant); 44 | game.trees.add(tree); 45 | } 46 | 47 | game.possibleActions.clear(); 48 | int numberOfPossibleActions = in.nextInt(); 49 | in.nextLine(); 50 | for (int i = 0; i < numberOfPossibleActions; i++) { 51 | String possibleAction = in.nextLine(); 52 | game.possibleActions.add(Action.parse(possibleAction)); 53 | } 54 | 55 | Action action = game.getNextAction(); 56 | System.out.println(action); 57 | } 58 | } 59 | } 60 | 61 | class Cell { 62 | 63 | int index; 64 | int richness; 65 | int[] neighbours; 66 | 67 | public Cell(int index, int richness, int[] neighbours) { 68 | this.index = index; 69 | this.richness = richness; 70 | this.neighbours = neighbours; 71 | } 72 | } 73 | 74 | class Tree { 75 | 76 | int cellIndex; 77 | int size; 78 | boolean isMine; 79 | boolean isDormant; 80 | 81 | public Tree(int cellIndex, int size, boolean isMine, boolean isDormant) { 82 | this.cellIndex = cellIndex; 83 | this.size = size; 84 | this.isMine = isMine; 85 | this.isDormant = isDormant; 86 | } 87 | } 88 | 89 | class Action { 90 | 91 | static final String WAIT = "WAIT"; 92 | static final String SEED = "SEED"; 93 | static final String GROW = "GROW"; 94 | static final String COMPLETE = "COMPLETE"; 95 | String type; 96 | Integer targetCellIdx; 97 | Integer sourceCellIdx; 98 | 99 | public Action(String type, Integer sourceCellIdx, Integer targetCellIdx) { 100 | this.type = type; 101 | this.targetCellIdx = targetCellIdx; 102 | this.sourceCellIdx = sourceCellIdx; 103 | } 104 | 105 | public Action(String type, Integer targetCellIdx) { 106 | this(type, null, targetCellIdx); 107 | } 108 | 109 | public Action(String type) { 110 | this(type, null, null); 111 | } 112 | 113 | static Action parse(String action) { 114 | String[] parts = action.split(" "); 115 | switch (parts[0]) { 116 | case WAIT: 117 | return new Action(WAIT); 118 | case SEED: 119 | return new Action(SEED, Integer.valueOf(parts[1]), Integer.valueOf(parts[2])); 120 | case GROW: 121 | case COMPLETE: 122 | default: 123 | return new Action(parts[0], Integer.valueOf(parts[1])); 124 | } 125 | } 126 | 127 | @Override 128 | public String toString() { 129 | if (WAIT.equalsIgnoreCase(type)) { 130 | return Action.WAIT; 131 | } 132 | if (SEED.equalsIgnoreCase(type)) { 133 | return String.format("%s %d %d", SEED, sourceCellIdx, targetCellIdx); 134 | } 135 | return String.format("%s %d", type, targetCellIdx); 136 | } 137 | } 138 | 139 | class Game { 140 | 141 | int day; 142 | int nutrients; 143 | List board; 144 | List possibleActions; 145 | List trees; 146 | int mySun, opponentSun; 147 | int myScore, opponentScore; 148 | boolean opponentIsWaiting; 149 | 150 | public Game() { 151 | board = new ArrayList<>(); 152 | possibleActions = new ArrayList<>(); 153 | trees = new ArrayList<>(); 154 | } 155 | 156 | Action getNextAction() { 157 | // TODO: write your algorithm here 158 | return possibleActions.get(0); 159 | } 160 | 161 | } -------------------------------------------------------------------------------- /starterAIs/starter.dart: -------------------------------------------------------------------------------- 1 | /// This a starter AIs to help new player written in Dart 2 | /// Use Dart version 2.12.4 which supports sound null safety. 3 | import 'dart:io'; 4 | 5 | void debug(Object obj) { 6 | stderr.writeln(obj); 7 | } 8 | 9 | class Cell { 10 | final int index; 11 | final int richness; 12 | final List neighbors; 13 | 14 | Cell(this.index, this.richness, this.neighbors); 15 | } 16 | 17 | class Tree { 18 | final int index; 19 | final int size; 20 | final bool isMine; 21 | final bool isDormant; 22 | 23 | Tree(this.index, this.size, this.isMine, this.isDormant); 24 | } 25 | 26 | class Action { 27 | static const String wait = 'WAIT'; 28 | static const String seed = 'SEED'; 29 | static const String grow = 'GROW'; 30 | static const String complete = 'COMPLETE'; 31 | 32 | final String type; 33 | final int? sourceCellIdx; 34 | final int? targetCellIdx; 35 | 36 | Action( 37 | this.type, [ 38 | this.targetCellIdx, 39 | this.sourceCellIdx, 40 | ]); 41 | 42 | static parse(String action) { 43 | debug(action); 44 | List parts = action.split(' '); 45 | 46 | switch (parts[0]) { 47 | case wait: 48 | return Action(wait); 49 | case seed: 50 | return Action(seed, int.parse(parts[2]), int.parse(parts[1])); 51 | default: 52 | return Action(parts[0], int.parse(parts[1])); 53 | } 54 | } 55 | 56 | @override 57 | String toString() { 58 | if (type == wait) { 59 | return wait; 60 | } else if (type == seed) { 61 | return '$seed $sourceCellIdx $targetCellIdx'; 62 | } else { 63 | return '$type $targetCellIdx'; 64 | } 65 | } 66 | } 67 | 68 | class Game { 69 | List board = []; 70 | List possibleActions = []; 71 | List trees = []; 72 | late int day; 73 | late int nutrients; 74 | late int mySun, opponentSun; 75 | late int myScore, opponentScore; 76 | late bool opponentIsWaiting; 77 | 78 | Game(); 79 | 80 | Action getNextAction() { 81 | // TODO: write your algorithm here 82 | return this.possibleActions[0]; 83 | } 84 | } 85 | 86 | String readLineSync() { 87 | String? s = stdin.readLineSync(); 88 | return s == null ? '' : s; 89 | } 90 | 91 | /** 92 | * Auto-generated code below aims at helping you parse 93 | * the standard input according to the problem statement. 94 | **/ 95 | void main() { 96 | Game game = Game(); 97 | 98 | List inputs; 99 | int numberOfCells = int.parse(readLineSync()); // 37 100 | for (int i = 0; i < numberOfCells; i++) { 101 | inputs = readLineSync().split(' '); 102 | int index = int.parse( 103 | inputs[0]); // 0 is the center cell, the next cells spiral outwards 104 | int richness = 105 | int.parse(inputs[1]); // 0 if the cell is unusable, 1-3 for usable cells 106 | int neigh0 = int.parse( 107 | inputs[2]); // the index of the neighbouring cell for each direction 108 | int neigh1 = int.parse(inputs[3]); 109 | int neigh2 = int.parse(inputs[4]); 110 | int neigh3 = int.parse(inputs[5]); 111 | int neigh4 = int.parse(inputs[6]); 112 | int neigh5 = int.parse(inputs[7]); 113 | 114 | List neighs = [neigh0, neigh1, neigh2, neigh3, neigh4, neigh5]; 115 | Cell cell = Cell(index, richness, neighs); 116 | 117 | game.board.add(cell); 118 | } 119 | 120 | // game loop 121 | while (true) { 122 | game.day = int.parse(readLineSync()); // the game lasts 24 days: 0-23 123 | game.nutrients = int.parse( 124 | readLineSync()); // the base score you gain from the next COMPLETE action 125 | inputs = readLineSync().split(' '); 126 | game.mySun = int.parse(inputs[0]); // your sun points 127 | game.myScore = int.parse(inputs[1]); // your current score 128 | inputs = readLineSync().split(' '); 129 | game.opponentScore = int.parse(inputs[0]); // opponent's sun points 130 | game.opponentScore = int.parse(inputs[1]); // opponent's score 131 | game.opponentIsWaiting = int.parse(inputs[2]) != 132 | 0; // whether your opponent is asleep until the next day 133 | 134 | game.trees.clear(); 135 | 136 | int numberOfTrees = 137 | int.parse(readLineSync()); // the current amount of trees 138 | for (int i = 0; i < numberOfTrees; i++) { 139 | inputs = readLineSync().split(' '); 140 | int cellIndex = int.parse(inputs[0]); // location of this tree 141 | int size = int.parse(inputs[1]); // size of this tree: 0-3 142 | bool isMine = int.parse(inputs[2]) != 0; // 1 if this is your tree 143 | bool isDormant = int.parse(inputs[3]) != 0; // 1 if this tree is dormant 144 | Tree tree = Tree(cellIndex, size, isMine, isDormant); 145 | game.trees.add(tree); 146 | } 147 | 148 | game.possibleActions.clear(); 149 | 150 | int numberOfPossibleActions = 151 | int.parse(readLineSync()); // all legal actions 152 | for (int i = 0; i < numberOfPossibleActions; i++) { 153 | String possibleAction = 154 | readLineSync(); // try printing something from here to start with 155 | game.possibleActions.add(Action.parse(possibleAction)); 156 | } 157 | 158 | // Write an action using print() 159 | // To debug: stderr.writeln('Debug messages...'); 160 | 161 | // GROW cellIdx | SEED sourceIdx targetIdx | COMPLETE cellIdx | WAIT 162 | Action action = game.getNextAction(); 163 | print(action); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /starterAIs/starter.ts: -------------------------------------------------------------------------------- 1 | class Cell { 2 | index: number; 3 | richness: number; 4 | neighbors: [number, number, number, number, number, number]; 5 | 6 | constructor( 7 | index: number, 8 | richness: number, 9 | neighbors: [number, number, number, number, number, number] 10 | ) { 11 | this.index = index; 12 | this.richness = richness; 13 | this.neighbors = neighbors; 14 | } 15 | } 16 | 17 | class Tree { 18 | cellIndex: number; 19 | size: number; 20 | isMine: boolean; 21 | isDormant: boolean; 22 | 23 | constructor( 24 | cellIndex: number, 25 | size: number, 26 | isMine: boolean, 27 | isDormant: boolean 28 | ) { 29 | this.cellIndex = cellIndex; 30 | this.size = size; 31 | this.isMine = isMine; 32 | this.isDormant = isDormant; 33 | } 34 | } 35 | 36 | const WAIT = 'WAIT'; 37 | const SEED = 'SEED'; 38 | const GROW = 'GROW'; 39 | const COMPLETE = 'COMPLETE'; 40 | 41 | type ACTION_TYPES = typeof WAIT | typeof SEED | typeof GROW | typeof COMPLETE; 42 | 43 | class Action { 44 | type: ACTION_TYPES; 45 | targetCellIdx: number; 46 | sourceCellIdx: number; 47 | 48 | constructor(type: typeof WAIT); 49 | 50 | constructor( 51 | type: typeof SEED, 52 | targetCellIdx: number, 53 | sourceCellIdx: number 54 | ); 55 | 56 | constructor(type: typeof GROW | typeof COMPLETE, targetCellIdx: number); 57 | 58 | constructor(type: string, targetCellIdx?: number, sourceCellIdx?: number); 59 | 60 | constructor( 61 | type: ACTION_TYPES, 62 | targetCellIdx?: number, 63 | sourceCellIdx?: number 64 | ) { 65 | this.type = type; 66 | this.targetCellIdx = targetCellIdx; 67 | this.sourceCellIdx = sourceCellIdx; 68 | } 69 | 70 | static parse(line: string) { 71 | const parts = line.split(' '); 72 | 73 | switch(parts[0]) { 74 | case WAIT: 75 | return new Action(WAIT); 76 | 77 | case SEED: 78 | return new Action(SEED, parseInt(parts[2]), parseInt(parts[1])); 79 | 80 | default: 81 | return new Action(parts[0], parseInt(parts[1])); 82 | } 83 | } 84 | 85 | toString() { 86 | if (this.type === WAIT) { 87 | return WAIT; 88 | } 89 | 90 | if (this.type === SEED) { 91 | return `${SEED} ${this.sourceCellIdx} ${this.targetCellIdx}`; 92 | } 93 | 94 | return `${this.type} ${this.targetCellIdx}`; 95 | } 96 | } 97 | 98 | class Game { 99 | round: number; 100 | nutrients: number; 101 | cells: Cell[]; 102 | possibleActions: Action[]; 103 | trees: Tree[]; 104 | mySun: number; 105 | myScore: number; 106 | opponentsSun: number; 107 | opponentScore: number; 108 | opponentIsWaiting: boolean; 109 | 110 | day: number; 111 | opponentSun: number; 112 | 113 | constructor() { 114 | this.round = 0; 115 | this.nutrients = 0; 116 | this.cells = []; 117 | this.possibleActions = []; 118 | this.trees = []; 119 | this.mySun = 0; 120 | this.myScore = 0; 121 | this.opponentsSun = 0; 122 | this.opponentScore = 0; 123 | this.opponentIsWaiting = false; 124 | } 125 | 126 | getNextAction() { 127 | // TODO: write your algorithm here 128 | return this.possibleActions[0]; 129 | } 130 | } 131 | 132 | const game = new Game(); 133 | 134 | const numberOfCells = parseInt(readline()); 135 | 136 | for (let i = 0; i < numberOfCells; i++) { 137 | var inputs = readline().split(' '); 138 | const index = parseInt(inputs[0]); 139 | const richness = parseInt(inputs[1]); 140 | const neigh0 = parseInt(inputs[2]); 141 | const neigh1 = parseInt(inputs[3]); 142 | const neigh2 = parseInt(inputs[4]); 143 | const neigh3 = parseInt(inputs[5]); 144 | const neigh4 = parseInt(inputs[6]); 145 | const neigh5 = parseInt(inputs[7]); 146 | 147 | game.cells.push( 148 | new Cell(index, richness, [ 149 | neigh0, 150 | neigh1, 151 | neigh2, 152 | neigh3, 153 | neigh4, 154 | neigh5, 155 | ]) 156 | ); 157 | } 158 | 159 | while (true) { 160 | game.day = parseInt(readline()); 161 | game.nutrients = parseInt(readline()); 162 | var inputs = readline().split(' '); 163 | game.mySun = parseInt(inputs[0]); 164 | game.myScore = parseInt(inputs[1]); 165 | var inputs = readline().split(' '); 166 | game.opponentSun = parseInt(inputs[0]); 167 | game.opponentScore = parseInt(inputs[1]); 168 | game.opponentIsWaiting = inputs[2] !== '0'; 169 | game.trees = []; 170 | 171 | const numberOfTrees = parseInt(readline()); 172 | 173 | for (let i = 0; i < numberOfTrees; i++) { 174 | var inputs = readline().split(' '); 175 | const cellIndex = parseInt(inputs[0]); 176 | const size = parseInt(inputs[1]); 177 | const isMine = inputs[2] !== '0'; 178 | const isDormant = inputs[3] !== '0'; 179 | 180 | game.trees.push(new Tree(cellIndex, size, isMine, isDormant)); 181 | } 182 | 183 | game.possibleActions = []; 184 | const numberOfPossibleAction = parseInt(readline()); 185 | 186 | for (let i = 0; i < numberOfPossibleAction; i++) { 187 | const possibleAction = readline(); 188 | game.possibleActions.push(Action.parse(possibleAction)); 189 | } 190 | 191 | const action = game.getNextAction(); 192 | 193 | console.log(action.toString()); 194 | } 195 | -------------------------------------------------------------------------------- /starterAIs/start2.scala: -------------------------------------------------------------------------------- 1 | import math._ 2 | import scala.util._ 3 | import scala.io.StdIn._ 4 | import scala.util.matching.Regex 5 | import scala.annotation.tailrec 6 | 7 | 8 | object Player extends App { 9 | import IOUtils._ 10 | 11 | val defaultCells = parseCells() 12 | 13 | // game loop 14 | while(true) { 15 | implicit val gameState = parseGameState(defaultCells) 16 | Wait().execute() 17 | 18 | // play(gameState) 19 | } 20 | } 21 | 22 | sealed abstract class Richness(val ord: Int) extends Ordered[Richness] { 23 | override def compare(that: Richness): Int = this.ord.compare(that.ord) 24 | } 25 | case object Unusable extends Richness(0) 26 | case object LowQuality extends Richness(1) 27 | case object MediumQuality extends Richness(2) 28 | case object HighQuality extends Richness(3) 29 | 30 | case class Cell(richness: Richness, neighbors: Vector[Int], tree: Option[Tree]) 31 | 32 | sealed abstract class Size(val ord: Int) extends Ordered[Size] { 33 | override def compare(that: Size): Int = this.ord.compare(that.ord) 34 | } 35 | case object Root extends Size(0) 36 | case object Small extends Size(1) 37 | case object Medium extends Size(2) 38 | case object Large extends Size(3) 39 | 40 | case class Tree( 41 | cellIndex: Int, 42 | size: Size, 43 | isMine: Boolean, 44 | isDormant: Boolean, 45 | ) 46 | 47 | case class GameState( 48 | day: Int, 49 | nutrients: Int, 50 | sun: Int, 51 | score: Int, 52 | oppSun: Int, 53 | oppScore: Int, 54 | oppIsWaiting: Boolean, 55 | cells: Vector[Cell], 56 | possibleMoves: Vector[Action], 57 | seedCost: Int, 58 | ) 59 | 60 | sealed abstract class Action { 61 | def execute(debugMsg: String = ""): Unit 62 | } 63 | 64 | object Action { 65 | val growSignature: Regex = """GROW (\d+)""".r 66 | val seedSignature: Regex = """SEED (\d+) (\d+)""".r 67 | val completeSignature: Regex = """COMPLETE (\d+)""".r 68 | val waitSignature: Regex = """WAIT""".r 69 | } 70 | 71 | case class Grow(index: Int, cell: Cell, cost: Int) extends Action { 72 | override def execute(debugMsg: String = ""): Unit = { 73 | println(s"GROW $index $debugMsg") 74 | } 75 | } 76 | 77 | case class Seed( 78 | sourceIndex: Int, 79 | destinationIndex: Int, 80 | sourceCell: Cell, 81 | destinationCell: Cell, 82 | ) extends Action { 83 | override def execute(debugMsg: String = ""): Unit = { 84 | println(s"SEED $sourceIndex $destinationIndex $debugMsg") 85 | } 86 | } 87 | 88 | case class Complete(index: Int, cell: Cell) extends Action { 89 | override def execute(debugMsg: String = ""): Unit = { 90 | println(s"COMPLETE $index $debugMsg") 91 | } 92 | } 93 | 94 | case class Wait() extends Action { 95 | override def execute(debugMsg: String = ""): Unit = { 96 | println(s"WAIT $debugMsg") 97 | } 98 | } 99 | 100 | object IOUtils { 101 | def parseCells(): Vector[Cell] = 102 | Vector.tabulate(readLine().toInt) { _ => 103 | val Array(index, richness, neigh0, neigh1, neigh2, neigh3, neigh4, neigh5) = (readLine() split " ").map (_.toInt) 104 | 105 | Cell( 106 | richness match { 107 | case 0 => Unusable 108 | case 1 => LowQuality 109 | case 2 => MediumQuality 110 | case 3 => HighQuality 111 | case _ => throw new IllegalArgumentException() 112 | }, 113 | neighbors = Vector(neigh0, neigh1, neigh2, neigh3, neigh4, neigh5), 114 | tree = None 115 | ) 116 | } 117 | 118 | def parseGameState(defaultCells: Vector[Cell]): GameState = { 119 | val day = readLine().toInt // the game lasts 24 days: 0-23 120 | val nutrients = readLine().toInt 121 | 122 | val Array(sun, score) = (readLine() split " ").map (_.toInt) 123 | 124 | val Array(_oppSun, _oppScore, _oppIsWaiting) = readLine() split " " 125 | val oppSun = _oppSun.toInt 126 | val oppScore = _oppScore.toInt 127 | val oppIsWaiting = _oppIsWaiting.toInt != 0 128 | 129 | val trees: Vector[Tree] = Vector.tabulate(readLine().toInt) { _ => 130 | val Array(_cellIndex, _size, _isMine, _isDormant) = readLine() split " " 131 | 132 | Tree( 133 | cellIndex = _cellIndex.toInt, 134 | size = _size.toInt match { 135 | case 0 => Root 136 | case 1 => Small 137 | case 2 => Medium 138 | case 3 => Large 139 | case _ => throw new IllegalArgumentException() 140 | }, 141 | isMine = _isMine.toInt != 0, 142 | isDormant = _isDormant.toInt != 0, 143 | ) 144 | } 145 | 146 | val growCost: Map[Size, Int] = Map( 147 | Root -> (1 + trees.count(t => t.size == Small && t.isMine)), 148 | Small -> (3 + trees.count(t => t.size == Medium && t.isMine)), 149 | Medium -> (7 + trees.count(t => t.size == Large && t.isMine)), 150 | ) 151 | 152 | val seedCost: Int = trees.count(t => t.isMine && t.size == Root) 153 | 154 | val indexedTrees = trees.groupBy(_.cellIndex).view.mapValues(_.head).toMap 155 | val cells = defaultCells.zipWithIndex.map { 156 | case (cell, index) => cell.copy(tree = indexedTrees.get(index)) 157 | } 158 | 159 | val possibleMoves = Vector.tabulate(readLine().toInt) { _ => 160 | readLine() match { 161 | case Action.growSignature(index) => Grow(index.toInt, cells(index.toInt), growCost(cells(index.toInt).tree.get.size)) 162 | case Action.seedSignature(source, destination) => Seed(source.toInt, destination.toInt, cells(source.toInt), cells(destination.toInt)) 163 | case Action.completeSignature(index) => Complete(index.toInt, cells(index.toInt)) 164 | case Action.waitSignature() => Wait() 165 | case _ => throw new IllegalArgumentException() 166 | } 167 | } 168 | 169 | GameState(day, nutrients, sun, score, oppSun, oppScore, oppIsWaiting, cells, possibleMoves, seedCost) 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/resources/view/assets/sleep_red.json: -------------------------------------------------------------------------------- 1 | {"frames":{"Dort_Red0001":{"frame":{"x":0,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0003":{"frame":{"x":0,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0005":{"frame":{"x":248,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0007":{"frame":{"x":248,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0009":{"frame":{"x":0,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0011":{"frame":{"x":248,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0013":{"frame":{"x":496,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0015":{"frame":{"x":496,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0017":{"frame":{"x":496,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0019":{"frame":{"x":0,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0021":{"frame":{"x":248,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0023":{"frame":{"x":496,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0025":{"frame":{"x":744,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0027":{"frame":{"x":744,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0029":{"frame":{"x":744,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0031":{"frame":{"x":744,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0033":{"frame":{"x":0,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0035":{"frame":{"x":248,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0037":{"frame":{"x":496,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0039":{"frame":{"x":744,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0041":{"frame":{"x":992,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0043":{"frame":{"x":992,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0045":{"frame":{"x":992,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0047":{"frame":{"x":992,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0049":{"frame":{"x":992,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0051":{"frame":{"x":0,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0053":{"frame":{"x":248,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0055":{"frame":{"x":496,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0057":{"frame":{"x":744,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0059":{"frame":{"x":992,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0061":{"frame":{"x":1240,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0063":{"frame":{"x":1240,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0065":{"frame":{"x":1240,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0067":{"frame":{"x":1240,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_Red0069":{"frame":{"x":1240,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}}},"meta":{"app":"https://www.leshylabs.com/apps/sstool/","version":"Leshy SpriteSheet Tool v0.8.4","image":"sleep_red.png","size":{"w":1488,"h":1404},"scale":1}} -------------------------------------------------------------------------------- /src/main/resources/view/assets/sleep_blue.json: -------------------------------------------------------------------------------- 1 | {"frames":{"Dort_BLUE0001":{"frame":{"x":0,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0003":{"frame":{"x":0,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0005":{"frame":{"x":248,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0007":{"frame":{"x":248,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0009":{"frame":{"x":0,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0011":{"frame":{"x":248,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0013":{"frame":{"x":496,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0015":{"frame":{"x":496,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0017":{"frame":{"x":496,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0019":{"frame":{"x":0,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0021":{"frame":{"x":248,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0023":{"frame":{"x":496,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0025":{"frame":{"x":744,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0027":{"frame":{"x":744,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0029":{"frame":{"x":744,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0031":{"frame":{"x":744,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0033":{"frame":{"x":0,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0035":{"frame":{"x":248,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0037":{"frame":{"x":496,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0039":{"frame":{"x":744,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0041":{"frame":{"x":992,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0043":{"frame":{"x":992,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0045":{"frame":{"x":992,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0047":{"frame":{"x":992,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0049":{"frame":{"x":992,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0051":{"frame":{"x":0,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0053":{"frame":{"x":248,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0055":{"frame":{"x":496,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0057":{"frame":{"x":744,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0059":{"frame":{"x":992,"y":1170,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0061":{"frame":{"x":1240,"y":0,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0063":{"frame":{"x":1240,"y":234,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0065":{"frame":{"x":1240,"y":468,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0067":{"frame":{"x":1240,"y":702,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}},"Dort_BLUE0069":{"frame":{"x":1240,"y":936,"w":248,"h":234},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":248,"h":234},"sourceSize":{"w":248,"h":234}}},"meta":{"app":"https://www.leshylabs.com/apps/sstool/","version":"Leshy SpriteSheet Tool v0.8.4","image":"sleep_blue.png","size":{"w":1488,"h":1404},"scale":1}} -------------------------------------------------------------------------------- /starterAIs/starter.vb: -------------------------------------------------------------------------------- 1 | Module Player 2 | Public Sub Main() 3 | Dim inputs As String() 4 | 5 | Dim Game As New Game 6 | 7 | Dim numberOfCells As Integer = CInt(Console.ReadLine()) ' 37 8 | For i As Integer = 0 To numberOfCells - 1 9 | inputs = Console.ReadLine().Split(" "c) 10 | Dim index = CInt(inputs(0)) ' 0 is the center cell, the next cells spiral outwards 11 | Dim richness = CInt(inputs(1)) ' 0 if the cell is unusable, 1-3 for usable cells 12 | Dim neigh0 = CInt(inputs(2)) ' the index of the neighbouring cell for each direction 13 | Dim neigh1 = CInt(inputs(2)) 14 | Dim neigh2 = CInt(inputs(2)) 15 | Dim neigh3 = CInt(inputs(2)) 16 | Dim neigh4 = CInt(inputs(2)) 17 | Dim neigh5 = CInt(inputs(2)) 18 | Next 19 | 20 | ' game loop 21 | While True 22 | Game.day = CInt(Console.ReadLine()) ' the game lasts 24 days: 0-23 23 | Game.nutrients = CInt(Console.ReadLine()) ' the base score you gain from the next COMPLETE Command 24 | inputs = Console.ReadLine().Split(" "c) 25 | Game.mySun = CInt(inputs(0)) ' your sun points 26 | Game.myScore = CInt(inputs(1)) ' your current score 27 | inputs = Console.ReadLine().Split(" "c) 28 | Game.opponentSun = CInt(inputs(0)) ' opponent's sun points 29 | Game.opponentScore = CInt(inputs(1)) ' opponent's score 30 | Game.opponentIsWaiting = inputs(2) <> "0" ' whether your opponent is asleep until the next day 31 | 32 | Game.trees.Clear() 33 | Dim numberOfTrees As Integer = CInt(Console.ReadLine()) ' the current amount of trees 34 | For i As Integer = 0 To numberOfTrees - 1 35 | inputs = Console.ReadLine().Split(" "c) 36 | Dim cellIndex As Integer = CInt(inputs(0)) ' location of this tree 37 | Dim size As Integer = CInt(inputs(1)) ' size of this tree: 0-3 38 | Dim isMine As Boolean = inputs(2) <> "0" ' 1 if this is your tree 39 | Dim isDormant As Boolean = inputs(3) <> "0" ' 1 if this tree is dormant 40 | Dim tree1 As New Tree(cellIndex, size, isMine, isDormant) 41 | Game.trees.Add(tree1) 42 | Next 43 | 44 | Game.possibleCommands.Clear() 45 | Dim numberOfPossibleMoves As Integer = CInt(Console.ReadLine()) 46 | For i As Integer = 0 To numberOfPossibleMoves - 1 47 | Dim possibleMove As String = Console.ReadLine() 48 | Game.possibleCommands.Add(Command.Parse(possibleMove)) 49 | Next 50 | 51 | Dim C As Command = Game.GetNextCommand() 52 | Console.WriteLine(C) 53 | 54 | End While 55 | End Sub 56 | End Module 57 | 58 | Class Game 59 | Public day As Integer 60 | Public nutrients As Integer 61 | Public board As List(Of Cell) 62 | Public possibleCommands As List(Of Command) 63 | Public trees As List(Of Tree) 64 | Public mySun, opponentSun As Integer 65 | Public myScore, opponentScore As Integer 66 | Public opponentIsWaiting As Boolean 67 | 68 | Public Sub New() 69 | board = New List(Of Cell) 70 | possibleCommands = New List(Of Command) 71 | trees = New List(Of Tree) 72 | End Sub 73 | 74 | Public Function GetNextCommand() As Command 75 | ' TODO: write your algorithm here 76 | Return possibleCommands.First() 77 | End Function 78 | End Class 79 | 80 | Class Cell 81 | Public index As Integer 82 | Public richess As Integer 83 | Public neighbours() As Integer 84 | 85 | Public Sub New(index As Integer, richess As Integer, neighbours() As Integer) 86 | Me.index = index 87 | Me.richess = richess 88 | Me.neighbours = neighbours 89 | End Sub 90 | End Class 91 | 92 | Class Tree 93 | Public cellIndex As Integer 94 | Public size As Integer 95 | Public isMine As Boolean 96 | Public isDormant As Boolean 97 | 98 | Public Sub New(cellIndex As Integer, size As Integer, isMine As Boolean, isDormant As Boolean) 99 | Me.cellIndex = cellIndex 100 | Me.size = size 101 | Me.isMine = isMine 102 | Me.isDormant = isDormant 103 | End Sub 104 | End Class 105 | 106 | Class Command 107 | Public Const WAIT As String = "WAIT" 108 | Public Const SEED As String = "SEED" 109 | Public Const GROW As String = "GROW" 110 | Public Const COMPLETE As String = "COMPLETE" 111 | 112 | Public Shared Function Parse(Command As String) As Command 113 | Dim parts As String() = Command.Split(" "c) 114 | Select Case parts(0) 115 | Case WAIT 116 | Return New Command(WAIT) 117 | Case SEED 118 | Return New Command(SEED, CInt(parts(1)), CInt(parts(2))) 119 | Case Else 120 | Return New Command(parts(0), CInt(parts(1))) 121 | End Select 122 | End Function 123 | 124 | Public type As String 125 | Public targetCellIdx As Integer 126 | Public sourceCellIdx As Integer 127 | 128 | Public Sub New(type As String) 129 | Me.New(type, 0, 0) 130 | End Sub 131 | 132 | Public Sub New(type As String, targetCellIdx As Integer) 133 | Me.New(type, 0, targetCellIdx) 134 | End Sub 135 | 136 | Public Sub New(type As String, sourceCellIdx As Integer, targetCellIdx As Integer) 137 | Me.type = type 138 | Me.targetCellIdx = targetCellIdx 139 | Me.sourceCellIdx = sourceCellIdx 140 | End Sub 141 | 142 | Public Overrides Function ToString() As String 143 | If type = WAIT Then 144 | Return Command.WAIT 145 | End If 146 | If type = SEED Then 147 | Return $"{SEED} {sourceCellIdx} {targetCellIdx}" 148 | End If 149 | 150 | Return $"{type} {targetCellIdx}" 151 | End Function 152 | End Class 153 | -------------------------------------------------------------------------------- /starterAIs/starter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.IO; 4 | using System.Text; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | 8 | class Cell 9 | { 10 | public int index; 11 | public int richness; 12 | public int[] neighbours; 13 | 14 | public Cell(int index, int richness, int[] neighbours) 15 | { 16 | this.index = index; 17 | this.richness = richness; 18 | this.neighbours = neighbours; 19 | } 20 | } 21 | 22 | class Tree 23 | { 24 | public int cellIndex; 25 | public int size; 26 | public bool isMine; 27 | public bool isDormant; 28 | 29 | public Tree(int cellIndex, int size, bool isMine, bool isDormant) 30 | { 31 | this.cellIndex = cellIndex; 32 | this.size = size; 33 | this.isMine = isMine; 34 | this.isDormant = isDormant; 35 | } 36 | } 37 | 38 | class Action 39 | { 40 | public const string WAIT = "WAIT"; 41 | public const string SEED = "SEED"; 42 | public const string GROW = "GROW"; 43 | public const string COMPLETE = "COMPLETE"; 44 | 45 | public static Action Parse(string action) 46 | { 47 | string[] parts = action.Split(" "); 48 | switch (parts[0]) 49 | { 50 | case WAIT: 51 | return new Action(WAIT); 52 | case SEED: 53 | return new Action(SEED, int.Parse(parts[1]), int.Parse(parts[2])); 54 | case GROW: 55 | case COMPLETE: 56 | default: 57 | return new Action(parts[0], int.Parse(parts[1])); 58 | } 59 | } 60 | 61 | public string type; 62 | public int targetCellIdx; 63 | public int sourceCellIdx; 64 | 65 | public Action(string type, int sourceCellIdx, int targetCellIdx) 66 | { 67 | this.type = type; 68 | this.targetCellIdx = targetCellIdx; 69 | this.sourceCellIdx = sourceCellIdx; 70 | } 71 | 72 | public Action(string type, int targetCellIdx) 73 | : this(type, 0, targetCellIdx) 74 | { 75 | } 76 | 77 | public Action(string type) 78 | : this(type, 0, 0) 79 | { 80 | } 81 | 82 | public override string ToString() 83 | { 84 | if (type == WAIT) 85 | { 86 | return Action.WAIT; 87 | } 88 | if (type == SEED) 89 | { 90 | return string.Format("{0} {1} {2}", SEED, sourceCellIdx, targetCellIdx); 91 | } 92 | return string.Format("{0} {1}", type, targetCellIdx); 93 | } 94 | } 95 | 96 | class Game 97 | { 98 | public int day; 99 | public int nutrients; 100 | public List board; 101 | public List possibleActions; 102 | public List trees; 103 | public int mySun, opponentSun; 104 | public int myScore, opponentScore; 105 | public bool opponentIsWaiting; 106 | 107 | public Game() 108 | { 109 | board = new List(); 110 | possibleActions = new List(); 111 | trees = new List(); 112 | } 113 | 114 | public Action GetNextAction() 115 | { 116 | // TODO: write your algorithm here 117 | return possibleActions.First(); 118 | } 119 | } 120 | 121 | class Player 122 | { 123 | static void Main(string[] args) 124 | { 125 | string[] inputs; 126 | 127 | Game game = new Game(); 128 | 129 | int numberOfCells = int.Parse(Console.ReadLine()); // 37 130 | for (int i = 0; i < numberOfCells; i++) 131 | { 132 | inputs = Console.ReadLine().Split(' '); 133 | int index = int.Parse(inputs[0]); // 0 is the center cell, the next cells spiral outwards 134 | int richness = int.Parse(inputs[1]); // 0 if the cell is unusable, 1-3 for usable cells 135 | int neigh0 = int.Parse(inputs[2]); // the index of the neighbouring cell for each direction 136 | int neigh1 = int.Parse(inputs[3]); 137 | int neigh2 = int.Parse(inputs[4]); 138 | int neigh3 = int.Parse(inputs[5]); 139 | int neigh4 = int.Parse(inputs[6]); 140 | int neigh5 = int.Parse(inputs[7]); 141 | int[] neighs = new int[] { neigh0, neigh1, neigh2, neigh3, neigh4, neigh5 }; 142 | Cell cell = new Cell(index, richness, neighs); 143 | game.board.Add(cell); 144 | } 145 | 146 | // game loop 147 | while (true) 148 | { 149 | game.day = int.Parse(Console.ReadLine()); // the game lasts 24 days: 0-23 150 | game.nutrients = int.Parse(Console.ReadLine()); // the base score you gain from the next COMPLETE action 151 | inputs = Console.ReadLine().Split(' '); 152 | game.mySun = int.Parse(inputs[0]); // your sun points 153 | game.myScore = int.Parse(inputs[1]); // your current score 154 | inputs = Console.ReadLine().Split(' '); 155 | game.opponentSun = int.Parse(inputs[0]); // opponent's sun points 156 | game.opponentScore = int.Parse(inputs[1]); // opponent's score 157 | game.opponentIsWaiting = inputs[2] != "0"; // whether your opponent is asleep until the next day 158 | 159 | game.trees.Clear(); 160 | int numberOfTrees = int.Parse(Console.ReadLine()); // the current amount of trees 161 | for (int i = 0; i < numberOfTrees; i++) 162 | { 163 | inputs = Console.ReadLine().Split(' '); 164 | int cellIndex = int.Parse(inputs[0]); // location of this tree 165 | int size = int.Parse(inputs[1]); // size of this tree: 0-3 166 | bool isMine = inputs[2] != "0"; // 1 if this is your tree 167 | bool isDormant = inputs[3] != "0"; // 1 if this tree is dormant 168 | Tree tree = new Tree(cellIndex, size, isMine, isDormant); 169 | game.trees.Add(tree); 170 | } 171 | 172 | game.possibleActions.Clear(); 173 | int numberOfPossibleMoves = int.Parse(Console.ReadLine()); 174 | for (int i = 0; i < numberOfPossibleMoves; i++) 175 | { 176 | string possibleMove = Console.ReadLine(); 177 | game.possibleActions.Add(Action.Parse(possibleMove)); 178 | } 179 | 180 | Action action = game.GetNextAction(); 181 | Console.WriteLine(action); 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /starterAIs/starter.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::fmt; 3 | 4 | macro_rules! parse_input { 5 | ($x:expr, $t:ident) => ($x.trim().parse::<$t>().unwrap()) 6 | } 7 | 8 | struct Tree { 9 | cell_index : i32, 10 | size : i32, 11 | is_mine : bool, 12 | is_dormant : bool, 13 | } 14 | 15 | type Forest = Vec; 16 | 17 | fn get_forest() -> Forest { 18 | let mut forest = vec![]; 19 | let mut input_line = String::new(); 20 | io::stdin().read_line(&mut input_line).unwrap(); 21 | let number_of_trees = parse_input!(input_line, i32); // the current amount of trees 22 | for i in 0..number_of_trees as usize { 23 | let mut input_line = String::new(); 24 | io::stdin().read_line(&mut input_line).unwrap(); 25 | let inputs = input_line.split(" ").collect::>(); 26 | let cell_index = parse_input!(inputs[0], i32); // location of this tree 27 | let size = parse_input!(inputs[1], i32); // size of this tree: 0-3 28 | let is_mine = parse_input!(inputs[2], i32) == 1; // 1 if this is your tree 29 | let is_dormant = parse_input!(inputs[3], i32) == 1; // 1 if this tree is dormant 30 | forest.push(Tree{cell_index, size, is_mine, is_dormant}); 31 | } 32 | forest 33 | } 34 | 35 | enum Action { 36 | Grow(i32), 37 | Seed(i32,i32), 38 | Complete(i32), 39 | Wait, 40 | } 41 | 42 | impl From<&String> for Action { 43 | fn from(s: &String) -> Self { 44 | let inputs = s.split(" ").collect::>(); 45 | match inputs[0] { 46 | "GROW" => Action::Grow(parse_input!(inputs[1], i32)), 47 | "SEED" => Action::Seed(parse_input!(inputs[1], i32),parse_input!(inputs[2], i32)), 48 | "COMPLETE" => Action::Complete(parse_input!(inputs[1], i32)), 49 | "WAIT" => Action::Wait, 50 | _ => {panic!("Wrong action input"); Action::Wait}, 51 | } 52 | } 53 | } 54 | 55 | impl fmt::Display for Action { 56 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 57 | write!(f, "{}", 58 | match self { 59 | Action::Grow(i) => format!("GROW {}", i), 60 | Action::Seed(i,j) => format!("SEED {} {}", i,j), 61 | Action::Complete(i) => format!("COMPLETE {}", i), 62 | Action::Wait => String::from("WAIT"), 63 | } 64 | ) 65 | } 66 | } 67 | 68 | type ActionList = Vec; 69 | 70 | fn get_actionlist() -> ActionList { 71 | let mut action_list = vec![]; 72 | let mut input_line = String::new(); 73 | io::stdin().read_line(&mut input_line).unwrap(); 74 | let number_of_possible_actions = parse_input!(input_line, i32); // all legal actions 75 | for i in 0..number_of_possible_actions as usize { 76 | let mut input_line = String::new(); 77 | io::stdin().read_line(&mut input_line).unwrap(); 78 | let possible_action = input_line.trim_matches('\n').to_string(); // try printing something from here to start with 79 | action_list.push(Action::from(&possible_action)); 80 | } 81 | action_list 82 | } 83 | 84 | struct GameContext { 85 | day : i32, 86 | nutrients : i32, 87 | sun : i32, 88 | score : i32, 89 | op_sun : i32, 90 | op_score : i32, 91 | op_is_waiting : bool, 92 | } 93 | 94 | fn get_game_context() -> GameContext { 95 | let mut input_line = String::new(); 96 | io::stdin().read_line(&mut input_line).unwrap(); 97 | let day = parse_input!(input_line, i32); // the game lasts 24 days: 0-23 98 | let mut input_line = String::new(); 99 | io::stdin().read_line(&mut input_line).unwrap(); 100 | let nutrients = parse_input!(input_line, i32); // the base score you gain from the next COMPLETE action 101 | let mut input_line = String::new(); 102 | io::stdin().read_line(&mut input_line).unwrap(); 103 | let inputs = input_line.split(" ").collect::>(); 104 | let sun = parse_input!(inputs[0], i32); // your sun points 105 | let score = parse_input!(inputs[1], i32); // your current score 106 | let mut input_line = String::new(); 107 | io::stdin().read_line(&mut input_line).unwrap(); 108 | let inputs = input_line.split(" ").collect::>(); 109 | let op_sun = parse_input!(inputs[0], i32); // opponent's sun points 110 | let op_score = parse_input!(inputs[1], i32); // opponent's score 111 | let op_is_waiting = parse_input!(inputs[2], i32) == 1; // whether your opponent is asleep until the next day 112 | 113 | GameContext{day, nutrients, sun, score, op_sun, op_score, op_is_waiting} 114 | } 115 | 116 | struct Cell { 117 | index : i32, 118 | richness : i32, 119 | neighbors_ids : Vec, 120 | } 121 | 122 | type Area = Vec; 123 | 124 | fn get_area() -> Area { 125 | let mut area = vec![]; 126 | let mut input_line = String::new(); 127 | io::stdin().read_line(&mut input_line).unwrap(); 128 | let number_of_cells = parse_input!(input_line, i32); // 37 129 | for i in 0..number_of_cells as usize { 130 | let mut input_line = String::new(); 131 | let mut neighbors_ids = vec![]; 132 | io::stdin().read_line(&mut input_line).unwrap(); 133 | let inputs = input_line.split(" ").collect::>(); 134 | let index = parse_input!(inputs[0], i32); // 0 is the center cell, the next cells spiral outwards 135 | let richness = parse_input!(inputs[1], i32); // 0 if the cell is unusable, 1-3 for usable cells 136 | let neigh_0 = parse_input!(inputs[2], i32); // the index of the neighbouring cell for each direction 137 | let neigh_1 = parse_input!(inputs[3], i32); 138 | let neigh_2 = parse_input!(inputs[4], i32); 139 | let neigh_3 = parse_input!(inputs[5], i32); 140 | let neigh_4 = parse_input!(inputs[6], i32); 141 | let neigh_5 = parse_input!(inputs[7], i32); 142 | for i in 2..8 { 143 | neighbors_ids.push(parse_input!(inputs[i], i32)); 144 | } 145 | area.push(Cell {index, richness, neighbors_ids}) 146 | } 147 | area 148 | } 149 | /** 150 | * Auto-generated code below aims at helping you parse 151 | * the standard input according to the problem statement. 152 | **/ 153 | fn main() { 154 | let area = get_area(); 155 | 156 | // game loop 157 | loop { 158 | let mut answer = String::from("WAIT"); 159 | 160 | let context = get_game_context(); // Get input context 161 | let forest = get_forest(); // Get input forest 162 | let action_list = get_actionlist(); // List of possible actions 163 | 164 | for s in action_list { 165 | eprintln!("Action : {}", s); 166 | } 167 | 168 | 169 | // GROW cellIdx | SEED sourceIdx targetIdx | COMPLETE cellIdx | WAIT 170 | println!("{}", answer); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /starterAIs/starter.php: -------------------------------------------------------------------------------- 1 | cells = []; 26 | // $numberOfCells: 37 27 | fscanf(STDIN, "%d", $this->numberOfCells); 28 | for ($i = 0; $i < $this->numberOfCells; $i++) { 29 | // $index: 0 is the center cell, the next cells spiral outwards 30 | // $richness: 0 if the cell is unusable, 1-3 for usable cells 31 | // $neigh0: the index of the neighbouring cell for each direction 32 | fscanf(STDIN, "%d %d %d %d %d %d %d %d", $index, $richness, $nb0, $nb1, $nb2, $nb3, $nb4, $nb5); 33 | $cell = new Cell(); 34 | $cell->index = $index; 35 | $cell->richness = $richness; 36 | $cell->neighbours = [$nb0, $nb1, $nb2, $nb3, $nb4, $nb5]; 37 | $this->cells[$index] = $cell; 38 | } 39 | } 40 | } 41 | 42 | class Tree 43 | { 44 | public $cellIndex = 0; 45 | public $size = 0; 46 | public $isMine = false; 47 | public $isDormant = false; 48 | public const MAX_SIZE = 3; 49 | public const HARVEST_SUNS = [0, 1, 2, 3]; 50 | 51 | // only for debugging 52 | public function toString(): string 53 | { 54 | return "[" . $this->cellIndex . ": " . $this->size 55 | . ($this->isMine ? " M" : " O") 56 | . ($this->isDormant ? " D" : " -") 57 | . "]"; 58 | } 59 | } 60 | 61 | class Action 62 | { 63 | public $verb = self::WAIT; 64 | public $index = 0; 65 | public $indexTo = 0; 66 | public $msg = ""; 67 | public const WAIT = 0; 68 | public const SEED = 1; 69 | public const GROW = 2; 70 | public const COMPLETE = 3; 71 | public const GROW_BASE_COSTS = [1, 3, 7]; 72 | public const COMPLETE_COST = 4; 73 | 74 | public function toString(): string 75 | { 76 | // GROW cellIdx | SEED sourceIdx targetIdx | COMPLETE cellIdx | WAIT 77 | if ($this->verb == self::WAIT) { 78 | $ans = "WAIT"; 79 | } elseif ($this->verb == self::SEED) { 80 | $ans = "SEED " . $this->index . " " . $this->indexTo; 81 | } elseif ($this->verb == self::GROW) { 82 | $ans = "GROW " . $this->index; 83 | } elseif ($this->verb == self::COMPLETE) { 84 | $ans = "COMPLETE " . $this->index; 85 | } else { 86 | throw new \Exception("Invalid action"); 87 | } 88 | if ($this->msg != "") { 89 | $ans .= " " . $this->msg; 90 | } 91 | return $ans; 92 | } 93 | } 94 | 95 | class Game 96 | { 97 | public $board = null; // Board 98 | public $day = 0; 99 | public $nutrients = 0; 100 | public $mySun = 0; 101 | public $myScore = 0; 102 | public $oppSun = 0; 103 | public $oppScore = 0; 104 | public $oppIsWating = false; 105 | public $numberOfTrees = 0; 106 | public $trees = []; // array[int idxCell] of Tree 107 | public $possibleMoves = []; // array of string 108 | public $action = null; // Action 109 | public const MAX_DAY = 24; 110 | public const EXTRA_POINT_PER_SUNS = 3; 111 | 112 | public function readTurnInput(): void 113 | { 114 | // $day: the game lasts 24 days: 0-23 115 | fscanf(STDIN, "%d", $this->day); 116 | // $nutrients: the base score you gain from the next COMPLETE action 117 | fscanf(STDIN, "%d", $this->nutrients); 118 | // $mySun: your sun points 119 | // $myScore: your current score 120 | fscanf(STDIN, "%d %d", $this->mySun, $this->myScore); 121 | // $oppSun: opponent's sun points 122 | // $oppScore: opponent's score 123 | // $oppIsWaiting: whether your opponent is asleep until the next day 124 | fscanf(STDIN, "%d %d %d", $this->oppSun, $this->oppScore, $oppIsWaiting); 125 | $this->oppIsWating = ($oppIsWaiting == 1); 126 | // $numberOfTrees: the current amount of trees 127 | fscanf(STDIN, "%d", $this->numberOfTrees); 128 | $this->trees = []; 129 | for ($i = 0; $i < $this->numberOfTrees; $i++) { 130 | // $cellIndex: location of this tree 131 | // $size: size of this tree: 0-3 132 | // $isMine: 1 if this is your tree 133 | // $isDormant: 1 if this tree is dormant 134 | fscanf(STDIN, "%d %d %d %d", $cellIndex, $size, $isMine, $isDormant); 135 | $tree = new Tree(); 136 | $tree->cellIndex = $cellIndex; 137 | $tree->size = $size; 138 | $tree->isMine = ($isMine == 1); 139 | $tree->isDormant = ($isDormant == 1); 140 | $this->trees[$cellIndex] = $tree; 141 | } 142 | fscanf(STDIN, "%d", $numberOfPossibleMoves); 143 | $this->possibleMoves = []; 144 | for ($i = 0; $i < $numberOfPossibleMoves; $i++) { 145 | $this->possibleMoves[] = stream_get_line(STDIN, 31 + 1, "\n"); 146 | } 147 | } 148 | 149 | public function output(): void 150 | { 151 | echo $this->action->toString(), PHP_EOL; 152 | } 153 | 154 | public function move(): void 155 | { 156 | $this->action = new Action(); // defaults to WAIT 157 | // TODO 158 | } 159 | 160 | // only for debugging 161 | public function logState(): void 162 | { 163 | error_log("====== Turn" 164 | . " [day: " . $this->day 165 | . ", nutr: " . $this->nutrients 166 | . ", trees: " . $this->numberOfTrees 167 | . "]"); 168 | error_log(" My: " . $this->mySun 169 | . " / " . $this->myScore 170 | . "; Opp: " . $this->oppSun 171 | . " / " . $this->oppScore 172 | . " / " . ($this->oppIsWaiting ? "W" : "-")); 173 | $s = ""; 174 | foreach ($this->trees as $tree) { 175 | $s .= $tree->toString() . "; "; 176 | } 177 | error_log(" Trees: " . $s); 178 | $s = ""; 179 | foreach ($this->possibleMoves as $move) { 180 | $s .= $move . "; "; 181 | } 182 | error_log(" Possible moves: " . $s); 183 | } 184 | } 185 | 186 | // --- MAIN --- 187 | $g = new Game(); 188 | $g->board = new Board(); 189 | $g->board->readInitInput(); 190 | while (true) { 191 | $g->readTurnInput(); 192 | // $g->logState(); 193 | $g->move(); 194 | $g->output(); 195 | } 196 | // To debug: error_log(var_export($var, true)); (equivalent to var_dump) 197 | -------------------------------------------------------------------------------- /src/main/resources/view/assets/debout_small.json: -------------------------------------------------------------------------------- 1 | {"frames":{"Debout_Red0001":{"frame":{"x":0,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0002":{"frame":{"x":0,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0003":{"frame":{"x":232,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0004":{"frame":{"x":232,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0005":{"frame":{"x":0,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0006":{"frame":{"x":232,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0007":{"frame":{"x":464,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0008":{"frame":{"x":464,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0009":{"frame":{"x":464,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0010":{"frame":{"x":0,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0011":{"frame":{"x":232,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0012":{"frame":{"x":464,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0013":{"frame":{"x":696,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0014":{"frame":{"x":696,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0015":{"frame":{"x":696,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0016":{"frame":{"x":696,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0017":{"frame":{"x":0,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0018":{"frame":{"x":232,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0019":{"frame":{"x":464,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0020":{"frame":{"x":696,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0021":{"frame":{"x":928,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0022":{"frame":{"x":928,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0023":{"frame":{"x":928,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0024":{"frame":{"x":928,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0025":{"frame":{"x":928,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0026":{"frame":{"x":0,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0027":{"frame":{"x":232,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0028":{"frame":{"x":464,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0029":{"frame":{"x":696,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0030":{"frame":{"x":928,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0031":{"frame":{"x":1160,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0032":{"frame":{"x":1160,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0033":{"frame":{"x":1160,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0034":{"frame":{"x":1160,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0035":{"frame":{"x":1160,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0036":{"frame":{"x":1160,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0037":{"frame":{"x":0,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0038":{"frame":{"x":232,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0039":{"frame":{"x":464,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0040":{"frame":{"x":696,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0041":{"frame":{"x":928,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0042":{"frame":{"x":1160,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0043":{"frame":{"x":1392,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0044":{"frame":{"x":1392,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0045":{"frame":{"x":1392,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0046":{"frame":{"x":1392,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0047":{"frame":{"x":1392,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0048":{"frame":{"x":1392,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0049":{"frame":{"x":1392,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0050":{"frame":{"x":0,"y":1582,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0051":{"frame":{"x":232,"y":1582,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Red0052":{"frame":{"x":464,"y":1582,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}}},"meta":{"app":"https://www.leshylabs.com/apps/sstool/","version":"Leshy SpriteSheet Tool v0.8.4","image":"debout_small.png","size":{"w":1624,"h":1808},"scale":1}} -------------------------------------------------------------------------------- /src/main/resources/view/assets/blue_idle.json: -------------------------------------------------------------------------------- 1 | {"frames":{"Debout_Blue0001":{"frame":{"x":0,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0002":{"frame":{"x":0,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0003":{"frame":{"x":232,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0004":{"frame":{"x":232,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0005":{"frame":{"x":0,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0006":{"frame":{"x":232,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0007":{"frame":{"x":464,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0008":{"frame":{"x":464,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0009":{"frame":{"x":464,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0010":{"frame":{"x":0,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0011":{"frame":{"x":232,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0012":{"frame":{"x":464,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0013":{"frame":{"x":696,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0014":{"frame":{"x":696,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0015":{"frame":{"x":696,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0016":{"frame":{"x":696,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0017":{"frame":{"x":0,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0018":{"frame":{"x":232,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0019":{"frame":{"x":464,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0020":{"frame":{"x":696,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0021":{"frame":{"x":928,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0022":{"frame":{"x":928,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0023":{"frame":{"x":928,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0024":{"frame":{"x":928,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0025":{"frame":{"x":928,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0026":{"frame":{"x":0,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0027":{"frame":{"x":232,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0028":{"frame":{"x":464,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0029":{"frame":{"x":696,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0030":{"frame":{"x":928,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0031":{"frame":{"x":1160,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0032":{"frame":{"x":1160,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0033":{"frame":{"x":1160,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0034":{"frame":{"x":1160,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0035":{"frame":{"x":1160,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0036":{"frame":{"x":1160,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0037":{"frame":{"x":0,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0038":{"frame":{"x":232,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0039":{"frame":{"x":464,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0040":{"frame":{"x":696,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0041":{"frame":{"x":928,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0042":{"frame":{"x":1160,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0043":{"frame":{"x":1392,"y":0,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0044":{"frame":{"x":1392,"y":226,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0045":{"frame":{"x":1392,"y":452,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0046":{"frame":{"x":1392,"y":678,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0047":{"frame":{"x":1392,"y":904,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0048":{"frame":{"x":1392,"y":1130,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0049":{"frame":{"x":1392,"y":1356,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0050":{"frame":{"x":0,"y":1582,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0051":{"frame":{"x":232,"y":1582,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}},"Debout_Blue0052":{"frame":{"x":464,"y":1582,"w":232,"h":226},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":232,"h":226},"sourceSize":{"w":232,"h":226}}},"meta":{"app":"https://www.leshylabs.com/apps/sstool/","version":"Leshy SpriteSheet Tool v0.8.4","image":"blue_idle.png","size":{"w":1624,"h":1808},"scale":1}} --------------------------------------------------------------------------------