3
\$\begingroup\$

I'm using printwriter to generate a LUA script for a tile map maker. It seems hackish to me, but it works.

Purposes are for allowing users to make their own maps for my game.

  • Is there a better practice to generate scripts?
  • Secondary - Why is it bad to do it my way?

I'm only including the function to write this Lua code, but if you want to run it on your own machine the full source is here.

public void buildLua() {
    block25 : {
        boolean foundGoal = false;
        boolean foundPlayer = false;
        boolean foundWall = false;
        int m = 0;
        while (!(foundGoal && foundPlayer && foundWall)) {
            if (this.mapGridList.get(m).getIcon().equals(this.goalIcon)) {
                foundGoal = true;
            } else if (this.mapGridList.get(m).getIcon().equals(this.playerIcon)) {
                foundPlayer = true;
            } else if (this.mapGridList.get(m).getIcon().equals(this.wallIcon)) {
                foundWall = true;
            }
            if (++m > (this.mapSize - 2) * (this.mapSize - 2)-1) break;
        }
        if (foundGoal && foundPlayer && foundWall) {
            try {
                JFileChooser chooser = new JFileChooser(String.valueOf(System.getProperty("user.home")) + "/Desktop");
                chooser.setFileSelectionMode(2);
                int result = chooser.showSaveDialog(chooser);
                if (result == 0) {
                    this.mapName = chooser.getSelectedFile().getName();
                    if (this.mapName.contains(".lua")) {
                        this.mapName = this.mapName.substring(0, this.mapName.length() - 4);
                    }
                    JRadioButton temp = new JRadioButton();                       
                    System.out.println(temp.getText());
                    this.setMaxWalls();
                    String path = chooser.getSelectedFile().getAbsolutePath();
                    PrintWriter writer = path.endsWith(".lua") ? new PrintWriter(path, "UTF-8") : new PrintWriter(String.valueOf(path) + ".lua", "UTF-8");
                    writer.println("local Map = IceRunner.Map");
                    writer.println("local MapKit = IceRunner.MapKit");
                    writer.println("local Up = IceRunner.MapTools.UpExtent");
                    writer.println("local Down = IceRunner.MapTools.DownExtent");
                    writer.println("local Left = IceRunner.MapTools.LeftExtent");
                    writer.println("local Right = IceRunner.MapTools.RightExtent");
                    writer.println("local Wall = IceRunner.Map.Wall");
                    writer.println("local MapKit = IceRunner.MapTools.MapKit");
                    writer.println("local Player = Map.Player");
                    writer.println("local Goal = Map.Goal");
                    writer.println("");
                    writer.println("local map = Map({");
                    writer.println("name = \"" + this.mapName.toUpperCase() + "\",");
                    writer.println("level = " + this.difficulty + ",");
                    writer.println("kit = MapKit({size = " + this.mapSize + ", walls = " + this.maxWalls + " })");
                    writer.println("})");
                    writer.println("");
                    if (this.mapSize == 15) {
                        writer.println("map:add_walls(Wall(0, 0), Right(14))");
                        writer.println("map:add_walls(Wall(1, 0), Down(13))");
                        writer.println("map:add_walls(Wall(1, 14), Down(13))");
                        writer.println("map:add_walls(Wall(14, 1), Right(13))");
                    } else if (this.mapSize == 20) {
                        writer.println("map:add_walls(Wall(0, 0), Right(19))");
                        writer.println("map:add_walls(Wall(1, 0), Down(18))");
                        writer.println("map:add_walls(Wall(1, 19), Down(18))");
                        writer.println("map:add_walls(Wall(19, 1), Right(18))");
                    } else if (this.mapSize == 25) {
                        writer.println("map:add_walls(Wall(0, 0), Right(24))");
                        writer.println("map:add_walls(Wall(1, 0), Down(23))");
                        writer.println("map:add_walls(Wall(1, 24), Down(23))");
                        writer.println("map:add_walls(Wall(24, 1), Right(23))");
                    }
                    int z = this.mapSize - 2;
                    int i = 1;
                    while (i < z * z + 1) {
                        int x;
                        int y;
                        if ((i - 1) % z > 0) {
                            x = (i - 1) / z;
                            y = (i - 1) % z;
                        } else {
                            x = (i - 1) / z;
                            y = 0;
                        }
                        if (this.mapGridList.get(i - 1).getIcon().equals(this.wallIcon)) {
                            writer.println("map:add_walls(Wall(" + (x + 1) + "," + (y + 1) + "), Up(0))");
                        } else if (this.mapGridList.get(i - 1).getIcon().equals(this.playerIcon)) {
                            writer.println("map:set_player(Player(" + (x + 1) + "," + (y + 1) + "))");
                        } else if (this.mapGridList.get(i - 1).getIcon().equals(this.goalIcon)) {
                            writer.println("map:set_goal(Goal(" + (x + 1) + "," + (y + 1) + "))");
                        }
                        ++i;
                    }
                    writer.println("");
                    writer.println("IceRunner.register_map(map);");
                    writer.close();

                    break block25;
                }
                JOptionPane.showMessageDialog(this.frmIceRunnerMap, "Map Not Saved!");
            }
            catch (IOException e) {
                JOptionPane.showMessageDialog(this.frmIceRunnerMap, "Error Occured While Saving!");
            }
        } else {
            JOptionPane.showMessageDialog(this.frmIceRunnerMap, "Please place at least one wall, start tile, and finish tile...");
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ in what area do you use these lua scripts? is it in a professional area or is it for private use? (that questions aims into 'how much time/money do you want to invest?') \$\endgroup\$ – Martin Frank Feb 16 '18 at 8:03
  • \$\begingroup\$ I am downvoting this question because I feel like we don't have enough information about what you want to do and why in order to help you the best. Can you add some more description about the use-case for this? \$\endgroup\$ – Simon Forsberg Feb 16 '18 at 16:03
1
\$\begingroup\$

I can't answer if there is a better way to generate a Lua script. Maybe you should google for some projects about connecting Java and Lua. I saw a bunch of them, so maybe someone already did what you need. But I'll mention how you can make your Java code better ;)

  1. Divide code into method

    You wrote a gigantic piece of code. It is hard to understand what is doing there. Believe me, when you leave your project and will go back later, you'll have difficulty with a full understanding of it.

    For instance, all those writer changes can be extracted to a method. Next example is the "setup" of player wall and goal. According to Clean Code by Robert Martin, a function should be no longer than 20 lines of code.

    Even extracting this to a method with parameter String message will make a positive change to the readable of code:

    JOptionPane.showMessageDialog(this.frmIceRunnerMap, "...");
    
  2. Stop using "magic numbers"

    On your GitHub repo (and even in this part of the code), there are some numbers. I tried to understand it but I can't.

    In map.java:

    for(int i = 0; i < 169; i++){
        JLabel label = new JLabel();
        label.setIcon(new ImageIcon(map.class.getResource("/team10/Empty.png")));
        panel.add(label);
    } 
    

    It would be nice to name those variables, like BoardSize. You can even create a separate class with those numbers and try to static import them to a class where they are used.

  3. Too much nested logic

    If you are using for in for in if etc. you are making code hard to understand. And for you, it will be hard to write some tests for your classes. The solution is our 1. point - dividing code. Maybe even add some additional classes.

At the beginning, it should be enough. Good luck :)

\$\endgroup\$
4
\$\begingroup\$

maybe you can push some of your code into a text file and use it to generate code?

template.txt:

local Map = IceRunner.Map
local MapKit = IceRunner.MapKit
local Up = IceRunner.MapTools.UpExtent
local Down = IceRunner.MapTools.DownExtent
...
local Goal = Map.Goal    
local map = Map({
    name = "{0}",
    level = "{1}",
    kit = MapKit({size = {2}, walls = {3} })
})

the MessageFormat class would replace the placeholders with your content:

String template = readFile("template.txt"); //please don't use hardcoded file names
String codePart = MessageFormat.format(
    template ,  //template with placeholders 
    this.mapName.toUpperCase(), // placeholder {0}
    this.difficulty, // placeholder {1}
    this.mapSize, // placeholder {2}
    this.maxWalls ); //placeholder {3}

...
writer.println(codePart); //lua-code with replaced placeholder

NOTE: the code for reading the template file (readFile()) is not part of my suggestion, please do on your own

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.