Scan and replace specific character with random position in text file in Java

I am trying to build a mini game and having problem with generating random stars in the map/maze. I have a method that will replace existing "**" to "0" , and I want it to replace any 5 random "0" with "*" again so that every time I run the program those stars will be generated randomly, but I can't figure out the algorithm. For example:

before
1111111111
1000*00001
1000000*01
10*0000*01
10000*0001
1111111111

after
1111111111
100*00*001
1*00000001
100000*001
100*000001
1111111111

Methods that im using currently,

 public static void main(String[] args) {
    cheeseReset("maze.txt", "*", "0");     
}

static void cheeseReset(String filePath, String oldString, String newString)
{
    File fileToBeModified = new File(filePath);
    String oldContent = "";
    BufferedReader reader = null;
    FileWriter writer = null;

    try
    {
        reader = new BufferedReader(new FileReader(fileToBeModified));
        String line = reader.readLine();
        while (line != null) 
        {
            oldContent = oldContent + line + System.lineSeparator();
            line = reader.readLine();
        }

        String newContent = oldContent.replace(oldString, newString); 
        //replace 5 random  "0" with "*"
        writer = new FileWriter(fileToBeModified);
        writer.write(newContent);      
    }

    catch (IOException e)
    {
        e.printStackTrace();
    }
    finally
    {
        try
        {
            reader.close();
            writer.close();
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        }
    }
}

2 answers

  • answered 2018-01-14 10:32 Bohemian

    You can use Math.random() or an instance of Random to generate random numbers, but you cannot control its output to cause exactly 5 of your map points to be stars with equal probability.

    However, you can chose exactly 5 with equal probability if you randomly re-order the points then use the first 5 after re-ordering.

    In pseudo code:

    • represent each point on your map with a single object (that has two points)
    • create a List and populate it with all points that can be a star
    • randomly reorder the list by calling Collections.shuffle(list)
    • place a star at the first 5 points of the list

  • answered 2018-01-14 10:32 tevemadar

    As you seem to know how to deal with files, I just show a way for the placement only, inspired by @Bohemian's answer, but a bit different:

    public class RandoMaze {
        public static final String ORGMAZE=
                  "11111111111111111  Stay\n"
                + "1*****@@@@0000001   'n'\n"
                + "1000000000000000111 Die\n"
                + "1000000000000000001\n"
                + "11111111111100000011111\n"
                + "           111000000001\n"
                + "Monsters     1110000001\n"
                + "everywhere     11111111\n";
        public static final Set<Character> SHUFFLEPIECES=new HashSet<>(Arrays.asList('0','@','*'));
        public static void main(String[] args) {
            System.out.println("Before:");
            System.out.println(ORGMAZE);
            char maze[]=ORGMAZE.toCharArray();
            List<Character> shuffleme=new ArrayList<>();
            for(int i=0;i<maze.length;i++)
                if(SHUFFLEPIECES.contains(maze[i]))
                    shuffleme.add(maze[i]);
            Collections.shuffle(shuffleme);
            for(int i=0;i<maze.length;i++)
                if(SHUFFLEPIECES.contains(maze[i]))
                    maze[i]=shuffleme.remove(0);
            System.out.println("After:");
            System.out.println(new String(maze));
        }
    }
    

    The idea is to have a representation of the playfield, built from a combination of items which are supposed to stay put (walls, 'decoration'), and items which are supposed to be randomized ('empty' fields, and objects).
    Then a loop extract the to-be-randomized objects only, shuffles them, and another loop puts them back (again working on the to-be-randomized fields only, leaving everything else intact).

    Note: that Set thing is particularly horrible, in real-life code it would be better to pick a continuous range of numbers/characters for representing 'movable' items, and check with a pair of <= and >=.