Sign in to follow this  
mepis

Help me with code ideas please?

Recommended Posts

mepis    230

Code is below, but first some background:

 

I'm hoping to make a game via the Construct 2 engine. It intrigues my so I want to play with it. I have an idea for a game that involves dungeon/maze generation. I want it to be random for replayability. It's the first time I've done something like this though (still very much a newb) so I went to prototype the idea of the generation in Java because I can form the logic easier. I figured I could translate it to Construct's events later on. I sat down and thought about doing it and my mind drew a blank. I figured the easiest way would be to use some type of recursive methods, and after looking into the idea of maze generation algorithms, it seems I was right. The problem is though that I can't do anything recursively. It has to be done through loops. I'm also building the maze in a 2D array so I can build the map from that. That means I need empty spaces between paths. The algorithms I was looking at didn't do this. I understand the idea of running through a loop with a structure but structure are a bit non-existent in Construct from what I can tell. I can build a second 2D parallel array to track where the maze has been but I was hoping not to so I could save memory and reduce garbage collection and stuff. I got completely stuck at this point so I just started throwing ideas at the IDE and saw what stuck.

 

Anyway, by a really happy mistake, I came up with the code below. Now, it's not really good to develop mazes. The output results in exactly what I ultimately aim to achieve though. I wanted random tunnels and random large rooms and caverns. I wanted the path to the exit different every time. I was planning on doing some other silly stuff once a maze was created, but this creates the output right away.  I ran through the algorithm a lot of times and adjusted the chokepoint to where it gives me a seemingly good result with a viable path every time (though I still have to write something to double check this each time. The code is very much a prototype but I wanted to get opinions on it, what looks crappy, what I could improve on. I'm still very much a newb so all the criticism I can get is good. Keep in mind I want to translate this to Construct 2 at some point though it doesn't bother me if you give me tips as if I was continuing this project in Java.

 

I thank anyone for their feedback. I really do appreciate it.


import java.util.Random;

public class Main {

	//These variables define the size of the maze.
	//Change only these to change the size of the maze
	private static final int ROWSIZE = 40;
	private static final int COLUMNSIZE = 40;
	
	public static void main(String[] args) {
		
		//variable declarations
		int[][] maze;
		int randX = 0;
		int randY = 0;
		int choke = 0;
		int checkSurroundings = 0;
		Random rand = new Random();
		maze = new int[ROWSIZE][COLUMNSIZE];
		
		//Initialize maze array to all zeros (make every space a non-moveable area)
		for (int x = 0;x < ROWSIZE; x++){
			for (int y = 0; y < COLUMNSIZE; y++){
				maze[x][y] = 0;
			}
		}
		
		//Define outside walls
		//Construct 2 specific:
		//We will use the number two to define all outside walls of maze so the game engine 
		//knows where to put these special tiles
		for (int x = 0; x < ROWSIZE; x++){
			maze[x][0] = 2;
			maze[x][COLUMNSIZE - 1] = 2;
		}
		for (int x = 0; x < COLUMNSIZE; x++){
			maze[0][x] = 2;
			maze[ROWSIZE - 1][x] = 2;
		}
		
		//Maze Generation
		randX = rand.nextInt(ROWSIZE - 10) + 5;
		maze[randX][0] = 1; //Mark beginning
		maze[randX][1] = 1;
		randX = rand.nextInt(ROWSIZE - 10) + 5;
		maze[randX][COLUMNSIZE - 1] = 1; //Mark ending
		maze[randX][COLUMNSIZE - 2] = 1;
		do {
			randX = rand.nextInt(ROWSIZE - 2) + 1;
			randY = rand.nextInt(COLUMNSIZE - 2) + 1;
			checkSurroundings = maze[randX - 1][randY] + maze[randX + 1][randY] + maze[randX][randY - 1] + maze[randX][randY + 1];		
			if (checkSurroundings < 4){
				maze[randX][randY] = 1;
				choke = 0;
			} else {
				choke ++;
			}
			
			
		} while (choke < 4); 
		
		//Print results of the maze array
		System.out.printf("\n");
		for (int x = 0; x < ROWSIZE; x++){
			for (int y = 0; y < COLUMNSIZE; y++){
				if (maze[x][y] == 0 || maze[x][y] == 2)
					System.out.printf("%d ", maze[x][y]);
				if (maze[x][y] == 1)
					System.out.printf("# ");
			}
			System.out.print("\n");
		}
	}
}

Share this post


Link to post
Share on other sites
the mole    119

You do not need to initialize everything with 0.

Java does that for you.

 

You only need to do that if each dimenson has a different size, but this is not the case.

int[][] maze = new int[ROW_SIZE][COLUMN_SIZE]; should initialize everything with 0.

The same for everything else.

 

I do not like ROWSIZE, I would prefer ROW_SIZE instead (the same for COLUMN_SIZE).

 

You could also use enum instead of 1,2,3 to indicate the "what" in your maze.

 

enum Type {

   Wall, Water, Tunnel, Whatever...;

}

 

Type[][] maze = new Type[ROW_SIZE][COLUMN_SIZE];

 

I have no idea how to generate dungeons, but you could try defining several "tunnels" or "dungeon parts" and simply concatenate them randomly.

 

Share this post


Link to post
Share on other sites
mepis    230

Thanks for the tips. Initializing everything to 0 was beaten into me in a high school programming class years ago. I've never shaken that habit. I like the criticism for everything else. That helps a lot.

 

I'm not sure if I can use enum. I'll have to go look at Construct again and see if there is a way to do something similar. Ultimately I plan to translate this to Construct for a game idea later on. That idea is being put on hold for the moment but I'll be getting back to it in the next few weeks. 

Share this post


Link to post
Share on other sites
richardurich    1352

First, you don't have anything wrong with your code. You are in great shape. Even the minor nitpicks I'll mention are just personal preference, and if you prefer otherwise than ignore the advice.

 

If you can't use enum, define constants and use them instead of literal numbers (like your ROW_SIZE and COLUMN_SIZE consts). It makes your code self-describing, which is a very good thing for readability and future debugging. I'd probably use constants for the 5 and 10 when getting a random X value too. I suggest that more for the self-documenting aspect than code clarity (it's already perfectly clear what you're doing). Named constants would just ensure ROW_SIZE has a reminder of constraints/assumptions on the value (can't be smaller than 10 in your code) in case you ever make it user-defined or whatever.

 

There's nothing wrong with initializing to zero. You'll want to initialize each maze element once you're using an enum or constant anyways since you wouldn't want your code to break just by changing the enum or constant from zero to one or something.

 

Most coding tips you'll figure out on your own. I could tell you to make a function for printing the maze since you'll want that functionality elsewhere, but you'd figure that out on your own pretty darn quick anyways. Your checkSurroundings calculation may break as your code evolves, but it'll be pretty obvious and you'll figure it out quickly. So I suppose my biggest advice is not to worry so much about what other coders think is "right" or "wrong" since you're doing great.

Share this post


Link to post
Share on other sites
d4n1    843

Readability should be your primary concern, unless readability greatly affects performance.  In JavaScript you'll be happy to have default values beaten into you.

 

Have you ever tried to make a minesweeper games just for giggles, you might find that a lot of the algorithms from that game will give you a nice boost of confidence for what you plan on doing.

Edited by d4n1

Share this post


Link to post
Share on other sites
mepis    230

Thanks guys! The kind words are nice to hear.

 

I think I might make a quick mine sweeper type protoype game in java then for the experience. I can understand why you'd say I would benefit from it. I don't think I would need to add a lot of polish to the game. It sounds like the learning experience would be in the algorithms to make the game work. It sounds like it would be a good experience. 

Share this post


Link to post
Share on other sites
mepis    230

Thank you d4n1!!!

 

So (and I apologize for the details now) I have been thinking about making a mindsweeper clone since I wrote the last post. I was taking a poop today and was thinking about the algorithms involved. I quickly stepped through it and thought of how I would roughly program it. Than it hit me that I could make random patterns of rooms and implement a corridor system with a very simple separate algorithm. It would create a much better effect than the code I have listed above and would ensure a random, but exact path through every single time! 

 

You're suggestion was awesome!

Share this post


Link to post
Share on other sites

Code is below, but first some background:
 
I'm hoping to make a game via the Construct 2 engine. It intrigues my so I want to play with it. I have an idea for a game that involves dungeon/maze generation. I want it to be random for replayability. It's the first time I've done something like this though (still very much a newb) so I went to prototype the idea of the generation in Java because I can form the logic easier. I figured I could translate it to Construct's events later on. I sat down and thought about doing it and my mind drew a blank. I figured the easiest way would be to use some type of recursive methods, and after looking into the idea of maze generation algorithms, it seems I was right. The problem is though that I can't do anything recursively. It has to be done through loops. I'm also building the maze in a 2D array so I can build the map from that. That means I need empty spaces between paths. The algorithms I was looking at didn't do this. I understand the idea of running through a loop with a structure but structure are a bit non-existent in Construct from what I can tell. I can build a second 2D parallel array to track where the maze has been but I was hoping not to so I could save memory and reduce garbage collection and stuff. I got completely stuck at this point so I just started throwing ideas at the IDE and saw what stuck.
 
Anyway, by a really happy mistake, I came up with the code below. Now, it's not really good to develop mazes. The output results in exactly what I ultimately aim to achieve though. I wanted random tunnels and random large rooms and caverns. I wanted the path to the exit different every time. I was planning on doing some other silly stuff once a maze was created, but this creates the output right away.  I ran through the algorithm a lot of times and adjusted the chokepoint to where it gives me a seemingly good result with a viable path every time (though I still have to write something to double check this each time. The code is very much a prototype but I wanted to get opinions on it, what looks crappy, what I could improve on. I'm still very much a newb so all the criticism I can get is good. Keep in mind I want to translate this to Construct 2 at some point though it doesn't bother me if you give me tips as if I was continuing this project in Java.
 
I thank anyone for their feedback. I really do appreciate it.

import java.util.Random;

public class Main {

	//These variables define the size of the maze.
	//Change only these to change the size of the maze
	private static final int ROWSIZE = 40;
	private static final int COLUMNSIZE = 40;
	
	public static void main(String[] args) {
		
		//variable declarations
		int[][] maze;
		int randX = 0;
		int randY = 0;
		int choke = 0;
		int checkSurroundings = 0;
		Random rand = new Random();
		maze = new int[ROWSIZE][COLUMNSIZE];
		
		//Initialize maze array to all zeros (make every space a non-moveable area)
		for (int x = 0;x < ROWSIZE; x++){
			for (int y = 0; y < COLUMNSIZE; y++){
				maze[x][y] = 0;
			}
		}
		
		//Define outside walls
		//Construct 2 specific:
		//We will use the number two to define all outside walls of maze so the game engine 
		//knows where to put these special tiles
		for (int x = 0; x < ROWSIZE; x++){
			maze[x][0] = 2;
			maze[x][COLUMNSIZE - 1] = 2;
		}
		for (int x = 0; x < COLUMNSIZE; x++){
			maze[0][x] = 2;
			maze[ROWSIZE - 1][x] = 2;
		}
		
		//Maze Generation
		randX = rand.nextInt(ROWSIZE - 10) + 5;
		maze[randX][0] = 1; //Mark beginning
		maze[randX][1] = 1;
		randX = rand.nextInt(ROWSIZE - 10) + 5;
		maze[randX][COLUMNSIZE - 1] = 1; //Mark ending
		maze[randX][COLUMNSIZE - 2] = 1;
		do {
			randX = rand.nextInt(ROWSIZE - 2) + 1;
			randY = rand.nextInt(COLUMNSIZE - 2) + 1;
			checkSurroundings = maze[randX - 1][randY] + maze[randX + 1][randY] + maze[randX][randY - 1] + maze[randX][randY + 1];		
			if (checkSurroundings < 4){
				maze[randX][randY] = 1;
				choke = 0;
			} else {
				choke ++;
			}
			
			
		} while (choke < 4); 
		
		//Print results of the maze array
		System.out.printf("\n");
		for (int x = 0; x < ROWSIZE; x++){
			for (int y = 0; y < COLUMNSIZE; y++){
				if (maze[x][y] == 0 || maze[x][y] == 2)
					System.out.printf("%d ", maze[x][y]);
				if (maze[x][y] == 1)
					System.out.printf("# ");
			}
			System.out.print("\n");
		}
	}
}

 
Nice code Mepis. The first thing I see where you could improve on is putting this code in a class, not in a main method.
 

You do not need to initialize everything with 0.
Java does that for you.

 
the mole is correct. But this is also more the reason why it should not be in main though. Their is something called the default constructor, which the JVM (Java Virtual Machine) creates for you when instantiating classes.  It is used to assign all primitives with a 0, 0.0 or null value. However, if you needed to override or overload the default constructor, you can. An example would be like this:

File 1.
public class Main{

    public static void main(String[] args){
        ClassExample ce1; = new ClassExample(); // Uses default constructor.
        int[][] maze = new int[40][40];
        ClassExample ce2; = new ClassExample(0, 0, 0, 0, maze); // Overloads default constructor.
    }
}

File 2
import java.util.Random;

public class ClassExample {
	
    // Your variables should look like this.
    private final int ROWSIZE = 40;
    private final int COLUMNSIZE = 40;
    private int[][] maze;
    private int randX;
    private int randY;
    private int choke;
    private int checkSurroundings;
    
    /*If you want to define a default value on creation of the class,
      you then want to override the default constructor like this.
    */
	public ClassExample() {

		randX = 0;
		randY = 0;
		choke = 0;
		checkSurroundings = 0;
		maze = new int[ROWSIZE][COLUMNSIZE]; // Will create instantiate on instantiate.
	}
	
	/*This will allow you to do the same thing as above but also allow
	  you to override the default values assigned in the default constructor
	  for reasons relating to making the code scalable. Remember, if you want 
	  to overload the default constructor, you need to override the default 
	  constructor first!
	*/
	public ClassExample(int x, int y, int choke, int cS, int[][] maze){
		this.randX = x;
		this.randY = y;
		this.choke = choke;
		this.checkSurroundings = cS;
		this.maze = maze;
	}

	// <-- Put your logic methods here.
	
	// Setters/Getters for all private class primatives.
	public int[][] getMaze() {
		return maze;
	}

	public void setMaze(int[][] maze) {
		this.maze = maze;
	}

	public int getRandX() {
		return randX;
	}

	public void setRandX(int randX) {
		this.randX = randX;
	}

	public int getRandY() {
		return randY;
	}

	public void setRandY(int randY) {
		this.randY = randY;
	}

	public int getChoke() {
		return choke;
	}

	public void setChoke(int choke) {
		this.choke = choke;
	}

	public int getCheckSurroundings() {
		return checkSurroundings;
	}

	public void setCheckSurroundings(int checkSurroundings) {
		this.checkSurroundings = checkSurroundings;
	}

	// Getters only for final primatives
	public int getROWSIZE() {
		return ROWSIZE;
	}

	public int getCOLUMNSIZE() {
		return COLUMNSIZE;
	}
}

Also, remember that static means global. You must assign a static value to any variable called outside of a method in the main class because of runtime limitations. This is useful for some reasons, but not in the way you are using it. If you create those variables in a sub class to main, they do not need to be static as seen in the example above.

 

Additionally, remember that you can use getters for final (constant) variables too, you just can't use setters because they are final.

 

Another good reason for using a subclass like this for the sake of being able to instantiate it multiple times.  For example, if you had a game with two players, and it was a race to see who could get through the maze faster, but one of the players was very experienced with your game, you may need to create a handicap for the more experienced. In this instance, you may want to overload the default constructor to make the maze size larger, thus creating two maze objects; one for each player with the larger maze going to the experienced player. Additionally, if you have to reuse the values stored in the instantiated objects, the values could remain the same since you could overload the default constructor. Or, if you needed to reset their values, you could also do this by instantiating with the default constructor. And finally, because the primitives are not static, their's less chance of exploitation. The above example are key points of overloading, overriding, encapsulation and polymorphism.

 

One more note: Try to get in the habit of using try/catch/finally. Here's an example:

	public boolean Game(){
		try {
			// <-- Put your logic here.
                        
                        // Example if only
			if(true){
				System.out.println(maze[500][500]); // Will create a null exception!
			}
			return true;
		} catch (Exception e) { // Will attempt to catch exception and keep application running.
			e.printStackTrace(); // Will tell you what happened.
			return false;
		}
	}

The key reasons for using try/catch/finally is it keeps the application running even if their is an exception, and it also makes your life easier to track down the bug. This greatly improves on quality assurance. Hope this helps.  Please feel free to add on to this in any way needed, or correct anywhere I am wrong.  Thanks!

Edited by Subtle_Wonders

Share this post


Link to post
Share on other sites
mepis    230

Thank you for the feedback subtle_wonders.  I didn't go to far into constructing the code with best practices for Java as I know them because I was only testing an idea. The algorithm may eventually be ported to Construct 2 for a game.

 

With that said though, I'm still very much a novice. I have a question. With Java best practices, is it always better to shove things into a separate class or is it acceptable, if the program is small, to keep it all in a single class? What's the pros and cons? 

 

I actually deviated at the moment as suggested to make a minesweeper game. The logic was a breeze to zip through and gave me some better ideas to implement somethings for a planned game down the road. It actually became a better exercise in the Java GUI classes. They still confuse me just because of how many there are. I got a really good intro to the grid bag layout. 

 

I digress though... While making the new minesweeper program I kept everything in a single class. I figured the program is small so it would create more work than needed for a program that doesn't really require any scaling later on. I separated everything into functions in the main class instead. I then made a lot of variables and objects as whole class variables and objects and labeled them as static. I did this because there would only ever be one game running at once and I would be destroying and remaking everything on resetting the game. My presumptions also guessed that doing this would make the program leaner on memory use and garbage collection. I was reading a bit on how Java and Javascript do this (two different languages, I know) and it was a practice on controlling that.

 

What are the thoughts on those ideas?

Share this post


Link to post
Share on other sites

Thank you for the feedback subtle_wonders.  I didn't go to far into constructing the code with best practices for Java as I know them because I was only testing an idea. The algorithm may eventually be ported to Construct 2 for a game.

 
Glad to be of some help.
 

I have a question. With Java best practices, is it always better to shove things into a separate class or is it acceptable, if the program is small, to keep it all in a single class? What's the pros and cons?

 
Best practice is to always put code in a separate object (that meaning not in the main class). That however does not necessarily mean it will provide the best result though; that being speed and only speed. An example of jamming stuff up in the main class is if you were creating a POJO (Plain Old Java Object) to substitute a output only BASH script in Linux/UNIX. Remember, the String[] args of the main parameter refer to the arguments taken in at the command prompt when typing in java someJavaMainClass. If let's say you created a POJO that was designed to run a sequence of Linux/UNIX commands using the getRunTime() method of the Runtime class (http://docs.oracle.com/javase/6/docs/api/), it may be practical to do so only in the main class. However, it is actually more efficient to do this in a language designed to work at a lower level of support, such as PERL, C/C++. as you are taking a unnecessary leap into a higher level language with the use of the JVM, which is developed largely in C++. It's like avoiding C++ to use C++, which simply doesn't make any sense and uses more memory in the process.
 
The rule of thumb is, if you need to instantiate even one object, then you are using Object Oriented Design, and it is best practice to adhere to it. If you're not, then it's kinda fruitless to use Java unless your environmental situation mandates it.
 

I got a really good intro to the grid bag layout.

 
AWT, Swing or Java FX? You should really jump on Java FX if your not currently using it. Java FX will at some point deprecate Swing, and AWT is mostly deprecated already. You should really learn how to use either Swing or Java FX from the source up, but if you ever needed to cheat: Ever hear of Java FX Scenebuilder (http://www.oracle.com/technetwork/java/javafx/tools/index.html).
 

I figured the program is small so it would create more work than needed for a program that doesn't really require any scaling later on.

 
This is typically a debate also found in C++. Both in C++ and in Java, the answer is the same; reader's simplicity. The moment you are referring to a part of your code as a separate English subject, that subject should be in a different class. For Example, if I was coding a game about cats, dogs, birds, and fish, I would have 6 classes:

  • Main (instantiates cat, dog and bird through animal)
  • Animal (abstract)
  • Cat (extends animal)
  • Dog (extends animal)
  • Bird (extends animal)
  • Fish (extends animal)

Methods (otherwise referred to as functions in C++) would refer to the characteristics of a class. Here is an example:

 
Cat (extends animal)

Sound() (makes a unique sound pertaining to the characteristics of the class defined)

Move() (moves in a unique way pertaining to the characteristics of the class defined)

Eat() (Eats unique food in a unique way to satisfy its appetite and physical needs)

 

Dog (extends animal)

Sound() (makes a unique sound pertaining to the characteristics of the class defined)

Move() (moves in a unique way pertaining to the characteristics of the class defined)

Eat() (Eats unique food in a unique way to satisfy its appetite and physical needs)

 

Bird (extends animal)

Sound() (makes a unique sound pertaining to the characteristics of the class defined)

Move() (moves in a unique way pertaining to the characteristics of the class defined)

Eat() (Eats unique food in a unique way to satisfy its appetite and physical needs)

 
Fish (extends animal)

Sound() (makes a unique sound pertaining to the characteristics of the class defined)

Move() (moves in a unique way pertaining to the characteristics of the class defined)

Eat() (Eats unique food in a unique way to satisfy its appetite and physical needs)

 

This is essentially important because, let us say that you now needed to consider which animal was a mammal (Dog, Cat), an aves (bird), and a paraphyletic (fish). This would be done using interface as you can extend only once from an abstract. In a more gamer sense, you could see it this way:

 
You have a mage (aka, wizard). You create an abstract of their AD&D class (necromancer, conjurer, enchanter, etc). However, their sortie of spells depend on an alignment, so you also create an alignments (evil, natural, good). You would abstract the wizard's AD&D class, and interface their alignment. The sortie of spells they use could then be considered based off of both the abstraction and inclusion of their associations (e.g., David, the Evil Necromancer [spells control the undead and unleash disease on helpless saps], John, the Good Necromancer [spells control the undead and allow him to siphon his own life force to heal a helpless sap], Brian, the Evil Wizard [spells that control the weather and use it to devastate the land because helpless saps should just be vaporized]).

 

Regardless if the project is large or small, if you don't look at it for a year, or someone else looks at it for you, it becomes extremely difficult to understand it quickly.
 


My presumptions also guessed that doing this would make the program leaner on memory use and garbage collection.

 
You are correct.
 

What are the thoughts on those ideas?

 
Their is a way to compromise between what you're trying to do and what Java is designed to do. I would recommend researching Singleton, and practicing on how to develop it and around it. For a small application, it's possible to get away with using a C++ practice in Java, but as projects get bigger, you will need to consider object management.
 
A Few Notes: Since we are talking about objects and memory:

 

Since you are creating a GUI: If you create a program that uses String, you are essentially creating an object. Most people know this. However, what most people do not know is every time you change the value of your String object, you are throwing away an object and creating a new String object. To get around this, you can use either StringBuffer (is thread safe) or StringBuilder (is not thread safe) as the object is unchanged when the value changes.
 
If you set an object to NULL and then declare System.gc(), you are likely to have that object destroyed much quicker than if it was just simply left as is. This is again, a good reason to use the try/catch/finally exception handling. In finally, you could create a clean up procedure, and later declare a System.gc() to schedule the destruction of that object you cleaned up. An example of where this could be used in your code is as follows:
 

After the last use of Random rand, use:

rand = null;
System.gc();

Over all, I see you doing a great job. For the size of your program, I'll assume it's fine enough to remain in the main class. I just don't want to see you get into the bad habit of using object evasion over object management. Hope this helps further. Also, thanks for the feedback.

Share this post


Link to post
Share on other sites
mepis    230

Ahh...  Thanks!  That put's things a little clearer than what's been explained in the past or in classes. It's given me a bit to chew over for the future. It's also given me a more concrete reason to organize in objects. I've always been told to just do it. It's never made sense why creating multiple objects for a single use, small program made sense though. I always thought it would make more sense to separate the code into methods/functions for a tiny program (sub 150 lines) to make the program more concise and easier to follow. 

 

I figured JavaFX was becoming the newer standard. I didn't read anything pointing at that though. There's so much information out there. That's my biggest issues, is reading and organizing all that information. It seems as if there is a different opinion or paradigm for everything.  I was also using the grid bag layout from AWT I believe. I'm not to far into the program, nor is it complicated. I might scrap it and rewrite in JavaFX. That might solve a problem I was having with buttons no being destroyed and recreated properly. Nonetheless, If I continue to have the issue I think I would rather have it with newer standard. That way when I learn the resolution it's more relevant.

 

I've run across the idea of a singleton pattern. Now I'll read about it. It sounds as if it could be a useful paradigm to learn.

 

Thanks again! I know it takes a bit of time to write all that out and you offered it to me for free. I really appreciate it!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this