CodinGame / codingame-game-engine

CodinGame Engine
https://www.codingame.com
MIT License
110 stars 41 forks source link

Can't run in local if the agent has an inner class in it #68

Open Butanium opened 1 year ago

Butanium commented 1 year ago

Having this runner :


package Runners.tests;

import agents.moveDumb;
import com.codingame.gameengine.runner.MultiplayerGameRunner;

public class crashTestMove {
    public static void main(String[] args) {
        /* Multiplayer Game */
        MultiplayerGameRunner gameRunner = new MultiplayerGameRunner();
        gameRunner.addAgent(moveDumb.class);
        gameRunner.addAgent(moveDumb.class);
        gameRunner.setLeagueLevel(3);
        gameRunner.setSeed(3794553746263553451L);
        gameRunner.start();

    }
}

I get this erro : image

java.lang.IllegalAccessError: tried to access class agents.moveDumb$Empty from class Agent41436
    at Agent41436.main(moveDumb.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.codingame.gameengine.runner.JavaPlayerAgent$JavaAgentThread.run(JavaPlayerAgent.java:191)

The agent that provok this is

package agents;

import java.util.Scanner;

/**
 * Control your bots in order to destroy the enemy team !
 **/
@SuppressWarnings("InfiniteLoopStatement")
public
class moveDumb {
    static class Empty {
        public int x;
        public int y;
        public Empty(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int botPerPlayer = in.nextInt(); // the amount of bot you control
        int mapSize = in.nextInt();
        // game loop
        while (true) {
            StringBuilder result = new StringBuilder();
            new Empty(1,2);
            int allyBotAlive = in.nextInt(); // the amount of your bot which are still alive
            int totalEntities = in.nextInt(); // the amount of entities in the arena
            System.err.printf("%d allybots, %d entities", allyBotAlive, totalEntities);
            in.nextLine();
            for (int i = 0; i < totalEntities; i++) {
               in.nextLine();
            }
            for (int i = 0; i < allyBotAlive; i++) {
                int accRank = totalEntities;
                int accId = 0;
                int accDist = 0;
                int selfId = 0;
                for (int j = 0; j < totalEntities; j++) {
                    int entId = in.nextInt(); // the unique entity id
                    String entType = in.next(); // the entity type in a string. It can be ON_AIR | ALLY | ENEMY
                    int distMe = in.nextInt(); // approximate distance between the target and the current bot. Can be 0 to 3 for short, medium, long and out of range
                    int distMeRank = in.nextInt(); // entities are sorted by ascending order based on their distance to the current bot
                    int shieldComp = in.nextInt(); // -1 if the entity has more shield than the current bot, 0 if it's equal, 1 if your bot as more shield
                    int healthComp = in.nextInt(); // same as shieldComp but for the health
                    int totComp = in.nextInt(); // same as shieldComp but based on the sum of health+shield
                    if(entType.equals("ENEMY") && distMeRank<accRank) {
                        accId = entId;
                        accRank = distMeRank;
                        accDist = distMe;
                    }
                    if (entType.equals("ON_AIR")) {
                        selfId = entId;
                    }
                }
                result.append(selfId).append(" MOVE ").append(accId).append(";");
            }
            System.out.println(result);
        }
    }
}

The cause is the use of the Empty class. However, online, this player works perfectly. How can I make it work locally ?

CGjupoulton commented 1 year ago

Pretty sure the local java class agent runner will only work if there is a single class in your file, consider converting into inner class or you'll need to compile and run your java file in as a ComandLineAgent

On Thu, 25 Aug 2022, 22:18 Clement Dumas, @.***> wrote:

Having this runner :

package Runners.tests; import agents.moveDumb;import com.codingame.gameengine.runner.MultiplayerGameRunner; public class crashTestMove { public static void main(String[] args) { / Multiplayer Game / MultiplayerGameRunner gameRunner = new MultiplayerGameRunner(); gameRunner.addAgent(moveDumb.class); gameRunner.addAgent(moveDumb.class); gameRunner.setLeagueLevel(3); gameRunner.setSeed(3794553746263553451L); gameRunner.start();

}

}

I get this erro : [image: image] https://user-images.githubusercontent.com/55806347/186760030-f09f2f2c-6fd9-4160-8f57-9573d50cce91.png

java.lang.IllegalAccessError: tried to access class agents.moveDumb$Empty from class Agent41436 at Agent41436.main(moveDumb.java:26) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.codingame.gameengine.runner.JavaPlayerAgent$JavaAgentThread.run(JavaPlayerAgent.java:191)

The agent that provok this is

package agents; import java.util.Scanner; / Control your bots in order to destroy the enemy team ! @.("InfiniteLoopStatement")publicclass moveDumb { static class Empty { public int x; public int y; public Empty(int x, int y) { this.x = x; this.y = y; } } public static void main(String[] args) { Scanner in = new Scanner(System.in); int botPerPlayer = in.nextInt(); // the amount of bot you control int mapSize = in.nextInt(); // game loop while (true) { StringBuilder result = new StringBuilder(); new Empty(1,2); int allyBotAlive = in.nextInt(); // the amount of your bot which are still alive int totalEntities = in.nextInt(); // the amount of entities in the arena System.err.printf("%d allybots, %d entities", allyBotAlive, totalEntities); in.nextLine(); for (int i = 0; i < totalEntities; i++) { in.nextLine(); } for (int i = 0; i < allyBotAlive; i++) { int accRank = totalEntities; int accId = 0; int accDist = 0; int selfId = 0; for (int j = 0; j < totalEntities; j++) { int entId = in.nextInt(); // the unique entity id String entType = in.next(); // the entity type in a string. It can be ON_AIR | ALLY | ENEMY int distMe = in.nextInt(); // approximate distance between the target and the current bot. Can be 0 to 3 for short, medium, long and out of range int distMeRank = in.nextInt(); // entities are sorted by ascending order based on their distance to the current bot int shieldComp = in.nextInt(); // -1 if the entity has more shield than the current bot, 0 if it's equal, 1 if your bot as more shield int healthComp = in.nextInt(); // same as shieldComp but for the health int totComp = in.nextInt(); // same as shieldComp but based on the sum of health+shield if(entType.equals("ENEMY") && distMeRank<accRank) { accId = entId; accRank = distMeRank; accDist = distMe; } if (entType.equals("ON_AIR")) { selfId = entId; } } result.append(selfId).append(" MOVE ").append(accId).append(";"); } System.out.println(result); } } }

The cause is the use of the Empty class. However, online, this player works perfectly. How can I make it work locally ?

— Reply to this email directly, view it on GitHub https://github.com/CodinGame/codingame-game-engine/issues/68, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHQVR5VSRQHDUU65CJ744ZLV27IHLANCNFSM57UNFTEQ . You are receiving this because you are subscribed to this thread.Message ID: @.***>

Butanium commented 1 year ago

What do you mean by inner class ? Empty is already declared in the moveDumb class, which is the one used by the agent. I tried to move the class declaration inside the main :

public static void main(String[] args) {
        class Empty {
            public int x;
            public int y;
            public Empty(int x, int y) {
                this.x = x;
                this.y = y;
            }
        }
        ...

which throw this error :

java.lang.IllegalAccessError: tried to access class agents.moveDumb$1Empty from class Agent582577
    at Agent582577.main(moveDumb.java:27)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.codingame.gameengine.runner.JavaPlayerAgent$JavaAgentThread.run(JavaPlayerAgent.java:191)

I guess I'll have to do it with the command line.

I tried multiple command but none works :

String path = " C:\\Users\\Clement\\Documents\\coding\\codinGame\\clash-of-bits\\src\\test\\java\\"
gameRunner.addAgent(new String[]{"javac " + path + "agents\\moveDumb.java",
                "java -cp "+path+" agents.moveDumb"});
// or
gameRunner.addAgent(new String[]{"javac " + path + "agents\\moveDumb.java",
                        "java -cp "+path+"; agents.moveDumb"});
// or
gameRunner.addAgent("javac " + path + "agents\\moveDumb.java" + " & " +
                "java -cp "+path+"; agents.moveDumb");
// or
gameRunner.addAgent("javac " + path + "agents\\moveDumb.java" + " ; " +
                "java -cp "+path+" agents.moveDumb");

The 2 first fail at compilation and the 2 last fail at runtime.

What command do you use to run .java with the SDK ? Because in CMD the first serie works and in powershell the second works :

PS C:\Users\Clement\Documents\coding\codinGame\clash-of-bits> javac C:\Users\Clement\Documents\coding\codinGame\clash-of-bits\src\test\java\agents\moveD
umb.java
PS C:\Users\Clement\Documents\coding\codinGame\clash-of-bits> java -cp C:\Users\Clement\Documents\coding\codinGame\clash-of-bits\src\test\java\ agents.m
oveDumb 
2 3 23 23
23 allybots, 23 entities
CGjupoulton commented 1 year ago

You're right, maybe what I'm remembering is the opposite, that you mustn't have any inner classes because they are not accessible by the the runner, try extracting instead. I have no access to my pc right now (on mobile) so I can't lookup the java commandline for you

On Fri, 26 Aug 2022, 01:12 Clement Dumas, @.***> wrote:

What do you mean by inner class ? Empty is already declared in the moveDumb class, which is the one used by the agent. I tried to move the class declaration inside the main :

public static void main(String[] args) { class Empty { public int x; public int y; public Empty(int x, int y) { this.x = x; this.y = y; } } ...

which throw this error :

java.lang.IllegalAccessError: tried to access class agents.moveDumb$1Empty from class Agent582577 at Agent582577.main(moveDumb.java:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.codingame.gameengine.runner.JavaPlayerAgent$JavaAgentThread.run(JavaPlayerAgent.java:191)

I guess I'll have to do it with the command line.

I tried multiple command but none works :

String path = " C:\Users\Clement\Documents\coding\codinGame\clash-of-bits\src\test\java\agents\moveDumb"gameRunner.addAgent(new String[]{"javac "+ path + ".java", "java "+path});gameRunner.addAgent("javac "+ path + ".java && " + "java "+path)gameRunner.addAgent("javac "+ path + ".java; " + "java "+path)

What command do you use to run .java with the SDK ?

— Reply to this email directly, view it on GitHub https://github.com/CodinGame/codingame-game-engine/issues/68#issuecomment-1227843753, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHQVR5RZN2PVSHHDRXWNICLV274V7ANCNFSM57UNFTEQ . You are receiving this because you commented.Message ID: @.***>

Butanium commented 1 year ago

With the same runner as in the first comment it fails :

package agents;

import java.util.Scanner;

/**
 * Control your bots in order to destroy the enemy team !
 **/
class Empty {
    public int x;
    public int y;
    public Empty(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
public
class moveDumb {
    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        int botPerPlayer = in.nextInt(); // the amount of bot you control
        int mapSize = in.nextInt();
        // game loop
        while (true) {
            StringBuilder result = new StringBuilder();
            new Empty(1,2);
            int allyBotAlive = in.nextInt(); // the amount of your bot which are still alive
            int totalEntities = in.nextInt(); // the amount of entities in the arena
            System.err.printf("%d allybots, %d entities", allyBotAlive, totalEntities);
            in.nextLine();
            for (int i = 0; i < totalEntities; i++) {
               in.nextLine();
            }
            for (int i = 0; i < allyBotAlive; i++) {
                int accRank = totalEntities;
                int accId = 0;
                int accDist = 0;
                int selfId = 0;
                for (int j = 0; j < totalEntities; j++) {
                    int entId = in.nextInt(); // the unique entity id
                    String entType = in.next(); // the entity type in a string. It can be ON_AIR | ALLY | ENEMY
                    int distMe = in.nextInt(); // approximate distance between the target and the current bot. Can be 0 to 3 for short, medium, long and out of range
                    int distMeRank = in.nextInt(); // entities are sorted by ascending order based on their distance to the current bot
                    int shieldComp = in.nextInt(); // -1 if the entity has more shield than the current bot, 0 if it's equal, 1 if your bot as more shield
                    int healthComp = in.nextInt(); // same as shieldComp but for the health
                    int totComp = in.nextInt(); // same as shieldComp but based on the sum of health+shield
                    if(entType.equals("ENEMY") && distMeRank<accRank) {
                        accId = entId;
                        accRank = distMeRank;
                        accDist = distMe;
                    }
                    if (entType.equals("ON_AIR")) {
                        selfId = entId;
                    }
                }
                result.append(selfId).append(" MOVE ").append(accId).append(";");
            }
            System.out.println(result);
        }
    }
}
java.lang.IllegalAccessError: tried to access class agents.Empty from class Agent991903
    at Agent991903.main(moveDumb.java:27)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.codingame.gameengine.runner.JavaPlayerAgent$JavaAgentThread.run(JavaPlayerAgent.java:191)

No hurry for the command line agent, I did all my testing with the uploaded contrib

CGjupoulton commented 1 year ago

Here use this:

    private static String compile(String botFile) throws IOException, InterruptedException {
        File outFolder = Files.createTempDir();

        System.out.println("Compiling " + botFile);
        Process compileProcess = Runtime.getRuntime()
            .exec(new String[] { "bash", "-c", "javac " + botFile + " -d " + outFolder.getAbsolutePath() });
        compileProcess.waitFor();
        return "java -cp " + outFolder + " Player";
    }

and use like this

   gameRunner.addAgent(compile("bots/Player.java"), "JavaBot");