// Path: src/main/java/pl/joegreen/sergeants/framework/Bot.java
// public interface Bot {
// 
//     /**
//      * Called on every game state update from server.
//      * @param newGameState Contains current state of the game.
//      */
//     default void onGameStateUpdate(GameState newGameState) {
//         getLogger(Bot.class).info("Received new game state: " + newGameState.toString());
//     }
// 
//     /**
//      * Called when game is won, lost or the connection to the server is lost.
//      * @param gameResult Result of the game.
//      */
//     default void onGameFinished(GameResult gameResult) {
//         getLogger(Bot.class).info("Game finished, result: " + gameResult);
//     }
// 
//     /**
//      * Called when the new game is started.
//      * @param gameStarted Contains basic info about the game (replay id, players in the game).
//      */
//     default void onGameStarted(GameStarted gameStarted) {
//         getLogger(Bot.class).info("Game started: " + gameStarted);
//     }
// 
//     /**
//      * Called on every chat message (game chat, team chat)
//      */
//     default void onChatMessage(ChatMessage chatMessage){
//         getLogger(Bot.class).info("Chat message: " + chatMessage);
//     }
// 
// }
// 
// Path: src/main/java/pl/joegreen/sergeants/framework/model/GameState.java
// public interface GameState extends GameStateFieldContext {
//     /**
//      * Horizontal size of the map. Does not change during the game.
//      */
//     int getColumns();
// 
//     /**
//      * Vertical size of the map. Does not change during the game.
//      */
//     int getRows();
// 
//     /**
//      * "Server turn" which is increased after every update (possibility of making a move). Is not the same as turn number
//      * displayed in browser (browser turn is equal to two server turns).
//      */
//     int getTurn();
// 
//     /**
//      * Officially "the attackIndex field is unnecessary for bots -- it's used by our client to show/hide attack arrows when appropriate."
//      * Some people say it can be used to find out state of moves queue and plan more complex moves ;-)
//      */
//     int getAttackIndex();
// 
//     /**
//      * Players currently playing and those already dead. Represents the table that is displayed in browser in the
//      * top right corner of the map.
//      */
//     ImmutableList<Player> getPlayers();
// 
//     ImmutableMap<Position, Field> getFieldsMap();
// 
//     GameStarted getGameStartedData();
// 
//     default Player getMyPlayer() {
//         return getPlayers().get(getMyPlayerIndex());
//     }
// 
//     default ImmutableMap<Position, VisibleField> getVisibleFieldsMap() {
//         return ImmutableMap.copyOf(getFieldsMap().values().stream()
//                 .filter(Field::isVisible)
//                 .map(Field::asVisibleField)
//                 .collect(Collectors.toMap(Field::getPosition, Functions.identity())));
//     }
// 
//     default Collection<Field> getFields() {
//         return getFieldsMap().values();
//     }
// 
//     default Collection<VisibleField> getVisibleFields() {
//         return getVisibleFieldsMap().values();
//     }
// 
//     default Field[][] getTwoDimensionalArrayOfFields() {
//         Field[][] array = new Field[getRows()][getColumns()];
//         for (int row = 0; row < getRows(); ++row) {
//             for (int col = 0; col < getColumns(); ++col) {
//                 array[row][col] = getFieldsMap().get(new Position(row, col));
//             }
//         }
//         return array;
//     }
// 
//     default Position positionFromIndex(int index) {
//         return Position.fromIndex(index, getColumns());
//     }
// 
//     default int positionToIndex(Position position) {
//         return position.toIndex(getColumns());
//     }
// 
//     default boolean isValidPosition(Position position) {
//         return position.getCol() < getColumns() && position.getCol() >= 0 && position.getRow() >= 0 && position.getRow() < getRows();
//     }
// 
//     default Set<Integer> getMyTeamIndexes() {
//         return getPlayers().stream().filter(
//                 player -> player.getTeam().equals(getPlayers().get(getMyPlayerIndex()).getTeam()))
//                 .mapToInt(Player::getIndex)
//                 .boxed()
//                 .collect(Collectors.toSet());
//     }
// 
// 
//     /**
//      * Index of bot's player.
//      */
//     default int getMyPlayerIndex() {
//         return getGameStartedData().getPlayerIndex();
//     }
// 
//     /**
//      * Replay identifier. Replays are available only after game is finished.
//      * Use http://bot.generals.io/replays/{replayId} to see the replay in your browser.
//      */
//     default String getReplayId() {
//         return getGameStartedData().getReplayId();
//     }
// 
//     /**
//      * Identifier of the main game chat room.
//      */
//     default String getChatRoom() {
//         return getGameStartedData().getChatRoom();
//     }
// 
//     /**
//      * Identifier of the private team chat room.
//      */
//     default String getTeamChatRoom() {
//         return getGameStartedData().getTeamChatRoom();
//     }
// 
//     default Set<Position> getNeighbourPositions(Position position) {
//         return Stream.of(
//                 position.withCol(position.getCol() + 1),
//                 position.withCol(position.getCol() - 1),
//                 position.withRow(position.getRow() + 1),
//                 position.withRow(position.getRow() - 1)
//         ).filter(this::isValidPosition).collect(Collectors.toSet());
//     }
// 
//     default Set<Field> getNeighbours(Field field) {
//         return getNeighbourPositions(field.getPosition())
//                 .stream()
//                 .map(this.getFieldsMap()::get)
//                 .collect(Collectors.toSet());
//     }
// 
// 
// 
// }


import pl.joegreen.sergeants.framework.Bot;
import pl.joegreen.sergeants.framework.model.GameState;
import java.util.ArrayList;
import java.util.List;
package pl.joegreen.sergeants.simulator;



public abstract class TestBot implements Bot {
    public final List<GameState> receivedGameStates = new ArrayList<>();

// Path: src/main/java/pl/joegreen/sergeants/framework/Bot.java
// public interface Bot {
// 
//     /**
//      * Called on every game state update from server.
//      * @param newGameState Contains current state of the game.
//      */
//     default void onGameStateUpdate(GameState newGameState) {
//         getLogger(Bot.class).info("Received new game state: " + newGameState.toString());
//     }
// 
//     /**
//      * Called when game is won, lost or the connection to the server is lost.
//      * @param gameResult Result of the game.
//      */
//     default void onGameFinished(GameResult gameResult) {
//         getLogger(Bot.class).info("Game finished, result: " + gameResult);
//     }
// 
//     /**
//      * Called when the new game is started.
//      * @param gameStarted Contains basic info about the game (replay id, players in the game).
//      */
//     default void onGameStarted(GameStarted gameStarted) {
//         getLogger(Bot.class).info("Game started: " + gameStarted);
//     }
// 
//     /**
//      * Called on every chat message (game chat, team chat)
//      */
//     default void onChatMessage(ChatMessage chatMessage){
//         getLogger(Bot.class).info("Chat message: " + chatMessage);
//     }
// 
// }
// 
// Path: src/main/java/pl/joegreen/sergeants/framework/model/GameState.java
// public interface GameState extends GameStateFieldContext {
//     /**
//      * Horizontal size of the map. Does not change during the game.
//      */
//     int getColumns();
// 
//     /**
//      * Vertical size of the map. Does not change during the game.
//      */
//     int getRows();
// 
//     /**
//      * "Server turn" which is increased after every update (possibility of making a move). Is not the same as turn number
//      * displayed in browser (browser turn is equal to two server turns).
//      */
//     int getTurn();
// 
//     /**
//      * Officially "the attackIndex field is unnecessary for bots -- it's used by our client to show/hide attack arrows when appropriate."
//      * Some people say it can be used to find out state of moves queue and plan more complex moves ;-)
//      */
//     int getAttackIndex();
// 
//     /**
//      * Players currently playing and those already dead. Represents the table that is displayed in browser in the
//      * top right corner of the map.
//      */
//     ImmutableList<Player> getPlayers();
// 
//     ImmutableMap<Position, Field> getFieldsMap();
// 
//     GameStarted getGameStartedData();
// 
//     default Player getMyPlayer() {
//         return getPlayers().get(getMyPlayerIndex());
//     }
// 
//     default ImmutableMap<Position, VisibleField> getVisibleFieldsMap() {
//         return ImmutableMap.copyOf(getFieldsMap().values().stream()
//                 .filter(Field::isVisible)
//                 .map(Field::asVisibleField)
//                 .collect(Collectors.toMap(Field::getPosition, Functions.identity())));
//     }
// 
//     default Collection<Field> getFields() {
//         return getFieldsMap().values();
//     }
// 
//     default Collection<VisibleField> getVisibleFields() {
//         return getVisibleFieldsMap().values();
//     }
// 
//     default Field[][] getTwoDimensionalArrayOfFields() {
//         Field[][] array = new Field[getRows()][getColumns()];
//         for (int row = 0; row < getRows(); ++row) {
//             for (int col = 0; col < getColumns(); ++col) {
//                 array[row][col] = getFieldsMap().get(new Position(row, col));
//             }
//         }
//         return array;
//     }
// 
//     default Position positionFromIndex(int index) {
//         return Position.fromIndex(index, getColumns());
//     }
// 
//     default int positionToIndex(Position position) {
//         return position.toIndex(getColumns());
//     }
// 
//     default boolean isValidPosition(Position position) {
//         return position.getCol() < getColumns() && position.getCol() >= 0 && position.getRow() >= 0 && position.getRow() < getRows();
//     }
// 
//     default Set<Integer> getMyTeamIndexes() {
//         return getPlayers().stream().filter(
//                 player -> player.getTeam().equals(getPlayers().get(getMyPlayerIndex()).getTeam()))
//                 .mapToInt(Player::getIndex)
//                 .boxed()
//                 .collect(Collectors.toSet());
//     }
// 
// 
//     /**
//      * Index of bot's player.
//      */
//     default int getMyPlayerIndex() {
//         return getGameStartedData().getPlayerIndex();
//     }
// 
//     /**
//      * Replay identifier. Replays are available only after game is finished.
//      * Use http://bot.generals.io/replays/{replayId} to see the replay in your browser.
//      */
//     default String getReplayId() {
//         return getGameStartedData().getReplayId();
//     }
// 
//     /**
//      * Identifier of the main game chat room.
//      */
//     default String getChatRoom() {
//         return getGameStartedData().getChatRoom();
//     }
// 
//     /**
//      * Identifier of the private team chat room.
//      */
//     default String getTeamChatRoom() {
//         return getGameStartedData().getTeamChatRoom();
//     }
// 
//     default Set<Position> getNeighbourPositions(Position position) {
//         return Stream.of(
//                 position.withCol(position.getCol() + 1),
//                 position.withCol(position.getCol() - 1),
//                 position.withRow(position.getRow() + 1),
//                 position.withRow(position.getRow() - 1)
//         ).filter(this::isValidPosition).collect(Collectors.toSet());
//     }
// 
//     default Set<Field> getNeighbours(Field field) {
//         return getNeighbourPositions(field.getPosition())
//                 .stream()
//                 .map(this.getFieldsMap()::get)
//                 .collect(Collectors.toSet());
//     }
// 
// 
// 
// }


// Path: src/test/java/pl/joegreen/sergeants/simulator/TestBot.java
import pl.joegreen.sergeants.framework.Bot;
import pl.joegreen.sergeants.framework.model.GameState;
import java.util.ArrayList;
import java.util.List;

package pl.joegreen.sergeants.simulator;



public abstract class TestBot implements Bot {
    public final List<GameState> receivedGameStates = new ArrayList<>();

    public void onGameStateUpdate(GameState newGameState) {