1

So I am making a text based rpg for a class. Currently the functionality is working for one room which is all I currently want. However I want a more efficient way of doing this. I want to do this without indexes. I want to print a list of elements from the text file from contains(3.a) to the point where end.3 is. Can any of you vets help me? . This is my first attempt at this type of project. The reason I am asking this early is because this is the intro into the project and the final project at the end of the semester will be a parsed 40 page text file.

The text file

1.a

Outside building
-------
WEST       2
UP         2
NORTH      3
IN         3

end.1

2.a

End of road
You are at the end of a road at the top of a small hill.
You can see a small building in the valley to the east.
------
EAST      1
DOWN      2

end.2

3.a

Inside building
You are inside a building, a well house for a large spring
-------
SOUTH    1
OUT      1

end.3

The code

public static void main(String[] args)throws FileNotFoundException{ 
    
    
    int direction = 0;
    Scanner s = new Scanner(new File("C:\\Users\\Basil Sheppard\\eclipse-workspace\\software practice\\src\\software\\rooms.txt"));
    Scanner choice = new Scanner(System.in);
    ArrayList<String> listS = new ArrayList<String>();
    

    while ( s.hasNextLine()) 
        listS.add(s.nextLine());
    
    
    System.out.println("please enter 3 for testing");
    direction = choice.nextInt();

    switch (direction){

//tests for room 3  
    case 3: {
    boolean found = listS.contains("3.a");
    if(found) {
        for(int i = 22; i<27; i++) {
            System.out.println(listS.get(i));
        }
    }
                            
} 
Loris Securo
  • 7,538
  • 2
  • 17
  • 28
  • 1
    You need to describe the file more. What are the numbers next to the NORTH, IN etc? – John Aug 19 '20 at 20:57
  • those are the directional inputs. eventually as it comes together I will implement light gui with a basic map that shows your location and the name of said location. I just edited it I realized there was no longer a user input line. – Basil Sheppard Aug 19 '20 at 21:03
  • For the first portion of this there will be 6 rooms. So If the user types 3 I want them to reach the point on the text file marked 3.a and print everything up to end.3 and so forth. I was considering a looped switch statement once I figure out the best way to implement this. If you have other ideas to do this rather than using contains I would love to try them. – Basil Sheppard Aug 19 '20 at 21:11
  • What you're describing is a terrible idea. Look at my answer. mapLocations[3] should hold 1 object, which is the MapLocation for the parsed data of 3.a -> end.3. The toString() method of this class should produce the output that you want to print on the screen. – John Aug 19 '20 at 21:30
  • I suggest using `java.nio` package, f.e. `Files.readAllLines()`. You should think of the input as a language. Language in the sense of a well-structured input. You need to capture this structure (into Java classes) and parse the input onto objects. If you would like to use some 3rd party library, you can definitely find some parser or parser generator. I myself have contributed to YAJCo where it is enough for you to define the classes and you get the parser for free. – Hawk Aug 19 '20 at 22:42

4 Answers4

1

Your approach looks entirely wrong.

What I would do:

  1. Create a class MapLocation, with the following:
    1. Title, String
    2. Description, String[]
    3. Navigation, MapNavi[]
  2. Create another class MapNavi, with the following:
    1. MapLoc, int
    2. Direction, String
  3. Read and parse entire file into MapLocation[]
  4. Process input and traverse MapLocation[]

The structure of the file seems to be:

(#.a

Title
Description Lines*
-------
MapNavi+

end.#)+

So you could either build a parser to process the file as above, which is quite trivial. You could also parse the entire file using purely RegEx.

Sample parser:

try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(_FILE_NAME))))
{
    String line;
    int state = 0;
    MapLocation currSegment = null;
    while ((line = br.readLine()) != null)
    {
        switch (state)
        {
        case 0:
           if (line.endsWith(".a"))
           {
               String segId = line.substring(0, line.indexOf(".a"));
               currSegment = new MapLocation(Integer.parseInt(segId));
               state++;
           }
           break;
        case 1:
           if (line.length() != 0)
           {
               currSegment.setTitle(line);
               state++;
           }
        case 2:
           if ("-------".equals(line))
           {
               state++;
           } else if (line.length() > 0)
           {
               currSegment.addDescription(line);
           }
        case 3:
           if (line.equals("end." + currSegment.getSegId()))
           {
               mapLocations.put(currSegment.getSegId(), currSegment);
               currSegment = null;
               state = 0;
           } else if (line.length() > 0)
           {
               String[] nav = line.split("\t");
               Integer mapLoc = Integer.parseInt(nav[1]);
               currSegment.addNavi(mapLoc, nav[0]);
           }
        }
    }
}

Once the file is parsed into the mapLocations container, you are ready to process input:

try (Scanner in = new Scanner(System.in))
{
    MapLocation currLoc = // startLocation;
    while (!quitSignal.equals(line = in.nextLine()))
    {
        int mapLoc = Integer.parseInt(line);
        if (currLoc.validateNav(mapLoc))
        {
            currLoc = mapLocations.get(mapLoc);
            System.out.println("You travel to " + currLoc.getTitle());
            System.out.println(currLoc.toString());
        }
        else
        {
            System.out.println("You cannot travel to location '" + line + "' from here.  Please re-select your destination.");
        }
    }
}
John
  • 800
  • 5
  • 11
  • For the past 20 minutes I have been looking at regex and I am attempting to understand how I could implement this in my project. Would you care to give a brief example? – Basil Sheppard Aug 19 '20 at 21:52
  • Regex would be an alternate parser to the parsing code above. It'd be something like the following pattern with multi-line support turned on: ((?[0-9]+).a\n+(?[^\n])\n(?<description>.+)?-------\n(?<nav>.+)\end.$segNr)+</nav></description> – John Aug 19 '20 at 22:02
0

You should look into storing your path as an xml file! Java has some cool ways to read them and it can understand elements in a list. You can even write to xml for easier constructing your game. Check this out for how to read in xml: https://stackoverflow.com/a/428091/9789673

randypaq13
  • 432
  • 3
  • 9
  • I would love to do that however the requirement is that it has to be a txt file. When i eventually do a personal project I will definitely look into that but the assignment requires txt files. – Basil Sheppard Aug 19 '20 at 21:02
  • Hmm ok there's a couple things you should do then imo. 1) create a custom parser for reading files all at once into some custom object. 2)create an object for storing different rooms. link these objects to each other ex for two adjacent rooms myRoom1.northRoom == myRoom2.southRoom etc 3) create a "game logic" loop that handles moving through the world and keeps track of game state and room object – randypaq13 Aug 19 '20 at 21:11
0

Try this.

try (Scanner s = new Scanner(new File("C:\\Users\\Basil Sheppard\\eclipse-workspace\\software practice\\src\\software\\rooms.txt"))) {
    Scanner choice = new Scanner(System.in);
    ArrayList<String> listS = new ArrayList<String>();

    while (s.hasNextLine())
        listS.add(s.nextLine());

     System.out.println("please enter 3 for testing");
    int direction = choice.nextInt();

    listS.stream()
        .dropWhile(x -> !x.equals(direction + ".a"))
        .takeWhile(x -> !x.equals("end." + direction))
        .forEach(System.out::println);
    System.out.println("end." + direction);
}

output

3.a

Inside building
You are inside a building, a well house for a large spring
-------
SOUTH    1
OUT      1

end.3

Note that .takeWhile(x -> !x.equals("end." + direction)) discards end.3 itself.

-1

I think you need to think about two main things:

  • Structure your file so that its lines have a fairly consistent structure that is easy to parse.
  • Think about how you can organise your code so that you only scan through the file once, creating classes to store the data in memory in an organised way the first time you read through the file. (Yes, in a sense, this is an "index", but you can't have it both ways: either you store/index information from the file the first time you scan it, or you throw the information away and have to scan through it again on the next query, which is inherently inefficient.)

For example, you might structure your file something like this:

BEGIN:LOCATION:1
BEGIN:DESCRIPTION:
A house.
END:DESCRIPTION
BEGIN:DIRECTIONS
NORTH:3
SOUTH:4
END:DIRECTIONS
END:LOCATION

In other words, the lines generally consist of 'command':'subcommand', and given a line in the file, it is fairly easy to split this into its components (look at String.indexOf(), String.substring(). If you can, look at the regular expressions API: see the Pattern and Matcher classes. (Theoretically, this can bring some efficiencies when you are trying to scan the same line/text for a number of different patterns/substrings simultaneously, and is the approach you'd generally use if you were scanning large volumes of text for more complex patterns/commands. For your purposes, you would also be fine with the simple String methods-- indexOf(), substring() etc-- if you find these easier to get to grips with.)

Others have mentioned XML: this is one a structured format that you could also consider, and comes with the advantage of standard parsing routines built into the Java platform. But there's nothing inherently wrong with a plain old text file in a format that you've devised so long as it's consistent and it's easy to write a routine to parse it...

Neil Coffey
  • 21,615
  • 7
  • 62
  • 83