OOPing

When I first started Java, my biggest confusion was how OOP (Object-Oriented Programming) worked; I was so used to the ways of Python and the others like it with how you can just write a file and everything would just run through line-by-line, not Object-by-Object. Hell I couldn’t even understand how you can do something like the following:

public class Foo {
    public static void main(String[] args) {
        Foo bar = new Foo();
        ...
    }
    ...
}

Code like this severely confused me at first. Why? Because you’re declaring a class and inside of its own code you’re making an object and then acting upon it, what’s not to find confusing at first coming from the worlds of Python and the like where you can just write something that’ll just run without the need of any “Objects” or whatever they call them? Well, that’s assuming no prior understanding to the topic of OOP.

Once it finally clicked how it all really worked, it all flowed smoothly from then on. I quickly learned quite a bit of it and adapted and learned the ways of OOP (I hope you pronounce it like I do, as a literal “oop” sound for fun), but I forgot to remember the very simple things such as the methods that each and every object inherits from class Object; this actually had me stuck for a while.

Back in the summer when I was starting my freetime Java project (a reincarnation of my old ‘py-txt-adv’ thing in Java), I decided to represent locations with an object I called Coordinates. Yes I knew about the Point object in awt, but I didn’t need something with all that it had, really only just x,y values with get/set methods (and maybe a distance method in the future).

Anyways, here’s how I initially defined it:

public class Coordinates {
	private int x, y;

	public Coordinates(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public int getX() { return x; }
	public int getY() { return y; }

	public void move(int x, int y) {
		this.x = x;
		this.y = y;
	}
}

Well this eventually stopped me when I tried comparing to see if two Coordinates objects were the same:

if(new Coordinates(0, 0) == new Coordinates(0, 0) { ... }

Well to any even amateur Java programmer it may be obvious as to why that wouldn’t work! Well thanks to my complete amateurism, I completely forgot about the default Object methods (especially Object.equals()) and could not figure out how to compare two of these objects of the same type, and I shouldn’t have even of had to remember that method and written my own that does that, but nooooooo, I had to think “outside the box”.

Well, I eventually thought about using some type of associative array which took me a while to figure out was a Map in Java. Why did I need this? Good question, actually. I thought what I had to do was have a static Map (HashMap to be specific) in the class that would get and create objects as needed. To get this to work I also needed to make it multidimensional, of which the only solution I could figure out was a Map inside of a Map. Here is what that code ended up looking like with comments and all (collapsed for your convenience):

package WorldLoader;
import java.util.*;

public class Coordinates {
	/*
	Coordinates object for easy global location representation.

	A Map of all objects made is created and a Coordinate object
	for a specific (x,y) set can be obtained through Coordinates.getObject(x, y).

	If the object for a specific set is not already created, it
	will be created and added to the Map automatically.

	coordinatesHashMap's Key is an Integer (x) and its Value is
	another HashMap (y) who's Key is an Integer (y) and its value
	is a Coordinate (x,y). The interior HashMap guarantees a different
	object because it is a different HashMap for each x value in
	the external HashMap.

	The current method is most likely not the
	best solution to this problem (mutable 2D associative array).
	Possible better solutions may be attempted soon.
	TODO: Find a better solution to the need of a 2D associative array.
	 */
	private int x, y;
	private static HashMap<Integer, HashMap<Integer, Coordinates>> coordinatesHashMap =
			new HashMap<Integer, HashMap<Integer, Coordinates>>();

	private Coordinates(int x, int y) {
		this.x = x;
		this.y = y;
	}
	public static Coordinates getObject(int x, int y) {
		if (coordinatesHashMap.containsKey(x)) {            // Check if x is already in.
			if (coordinatesHashMap.get(x).containsKey(y)) { // Check if y is already in.
				return coordinatesHashMap.get(x).get(y);    // If both are true, then there is an object.
			} else {
				coordinatesHashMap.get(x).put(y, new Coordinates(x, y));
				return coordinatesHashMap.get(x).get(y);
			}
		} else {
			coordinatesHashMap.put(x, new HashMap<Integer, Coordinates>());
			coordinatesHashMap.get(x).put(y, new Coordinates(x, y));
			return coordinatesHashMap.get(x).get(y);
		}
	}
	public int getX() { return x; }
	public int getY() { return y; }

	public String toString() {
		return "("+x+","+y+")";
	}
}

Eyesore, right? If you don’t get what the code is doing I believe the comments make it pretty clear. This is exactly what overthinking can get you. I ended up taking about one month off from the whole thing and just jumped back on a couple days ago and looked into this again, wondering, “jee, what is up with this?” In fact, I still didn’t see the huge flaw in it. Hell I still looked more into the whole “multidimensional associative array” thing in Java, eventually finding the Table object from the Guava libraries from Google and trying to duplicate those. Why was it that I did all this? So I could use == to compare two of these objects. It was only recently, just recently that I remembered of the Object.equals() method. Duh, just write a method that compares the two values! I felt so stupid at this realization not too long ago.

Anyways, figuring this out I added the Object.equals(Object o) and Object.hashCode() methods. So yeah, that was my mini adventure of learning not through fault, but through lack of experience. Here’s how the script ended up to (finally) being:

public class Coordinates {
	public final int x, y;

	public Coordinates(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public boolean equals(Object o) {
		if(o instanceof Coordinates) {
			return ((Coordinates) o).x == x && ((Coordinates) o).y == y;
		}
		return false;
	}

	public int hashCode() { return x * 31 + y * 17; }
}

Anyone have any other interesting learning experiences? Feel free to share past embarrassments.

Advertisements

SCHOOL

Fun, right? Finally it’s starting and hopefully I can finally make a complete project. I mostly want to do that to help myself start at the higher classes for CS rather than beginner ones. The project I’m not sure of, I did start on another text-based game engine in Java but I’m not sure if I will complete that or not or if I’ll just rewrite it from scratch again; I might just rewrite it because I do have some good ideas.

Hello again, World!

I have been away for a while, yes? I kind of abandoned this blog for a while due to my focus on school, music and other languages (mostly Java and Forth). This blog will likely remain dormant until August due to my summer being completely busy up until then. I hope to use this as a type of research journal type of thing for a typical college student as my major will be Computer Science; we’ll see.

Until then, tschüβ!

What I’ve been doing

For the past couple days I have paid only a little attention to my project but a lot towards Dale’s. I find working on someone else’s project is great practice for reading and interpreting unfamiliar code.

School starts very soon for me as well so chances are that more time on my project will be gone. After a few more commits to the project I will give more attention back to mine.

I would like to remind whoever is reading this that I am still learning Python and this project was simply me going crazy over small ideas which grew from an exercise; only very, very recently did I learn the basics of classes and OOP in Python. I would like to spend more time learning it and how to use it.

Python Text Adventure’s Future

As I have mentioned before, I do plan on eventually getting to the point of being a usable tool, however right now I have a mental list of ideas I am thinking up and finding ways to plug in (I should probably write them down somehow to protect from memory loss).

I have 2 branches right now, the master, which should be mostly working with the finished features, and hot. The hot branch is mostly for ‘hot’fixes, sudden additions, etc. Once I get it more stabilized I will make different branches for different features.

Here’s a list of current and future plans and thoughts for what to do:

  • Items: I have already started jotting down ideas in items.py which is in the hot branch. I am still figuring out how to get it implemented and how to use it and ways to use data, as well as how to do things such as dropped items.
  • Health/Armor: This is actually something I thought of while writing all this. It should be simple to implement so I won’t really talk about it.
  • NPC’s: Haven’t thought about much; I just know it’s something I’ll have to put in sometime.

That’s everything I could think of (for now) and if anything else comes to mind I’ll add it.

Please, if you have ANY ideas whatsoever, share!

How Python Text-Adventure Game Works

(A bit late to post this, I know.) Python Text-Adventure Game is an engine I am making in Python 2 as my first serious project for programming that I do plan to finish and to make usable for someone who might be interested in making such a game.

I’d like to add that this post is for the current code at the time of writing. So when this post becomes old and stale the code may be completely different.

game.py


This first file is where the main game loop occurs. First it imports locations and movement (both will be explained shortly) and then I define a currLoc function that just prints out the player’s current position in the game world; the coordinates are based off of an X,Y grid: X = East/West; Y = North/South. I call this function once and then starts the while True loop which is the game loop.

The while True works like this:

  1. Takes in user input as ui,
  2. Splits the inputed string at each space,
  3. Appends an empty string to protect against fallback

The next part checks what the command was, so if ui[0] ==

  • "go":
    • call the go function from movement, and
    • call the checkLoc function from locations
  • "look":
    • call the checkLoc function from locations, but have it print a different message
  • "quit":
    • exit the game
  • else:
    • depending on input, print a certain message.

Pretty simple, yes? I know, anyone out there who’s good at Python may find many dud things with it that can be made better, but for now I ask for no suggestions for the code directly but I will always be open for suggestions on features.

movement.py


This file gets a bit more complex and, although viewed as simple to someone with experience, I felt proud of myself on getting it all figured out and working as a newbie.

The first function I defined is limit which is what keeps players from going outside of the game world, although all it does is check if the player can go in the direction that was entered. The type of check it does is its parameter, which is either 1, 2, 3 or 4 and will return either true or false depending on the max values that are defined under the funcdoc string.

The next function, go, is everything to do with movement. It simply adds or subtracts 1 from X, Y or both depending on the direction entered (north, south, east, west). It first calls the limit function to check if it can, and will do so accordingly; if it cannot it simply returns a message.

After this mess is where the initial X,Y values are set, or the player’s starting position.

locations.py


locations.py is so far the most complex file in the project: it has a function (realize) that takes in either two or four coordinates which defines the corners of a square ‘area’ (meaning environments the player will explore; e.g. forest or cave) and will return a list that holds every coordinate in that area. Why I do it this way is so it can easily check if the current player position is ‘in‘ an area.

(Why I gave this function the name realize I’m not sure, I’m just not very good at names.)

realize:

  • First it makes two lists which will hold all of the X and Y numbers given by the second parameter (coords): coordsx and coordsy. This is done with a simple for loop.
  • Next it checks if just 2 or 4 coordinates were given (the function can work with either 2 coordinates that are diagonal from one-another or if all 4 are given). How it uses this is self-explanatory by reading the code.
  • The coordinates are sorted to easily get the lowest and highest numbers and assigns these numbers to the variables lx, hx, ly, hy which mean Low/High X/Y (probably another bad usage of names).
  • The if/elif logic here is just a sanity check and I have yet to learn proper error handling so until then I’m just using exit.
  • This is where the actual magic happens:
    • First the coords var is cleared and reset to an empty list for appending new values.
    • Depending on the first parameter (ty) it will either find all of the coordinates in an area (1) or it will find just the coordinates that are along the edges of an area (2).
    • For the first type of data to be returned, I have a while loop, although I am trying to figure out how to get it as a forloop instead (remember I am a newbie, give me time). Again, please no suggestions on the code for now as this is all a learning experience for me as I work on this, but I will explain how it works here:
      • I make a lyr var as a reset for the ly variable.
      • It is a bit hard to explain how the while loop does its thing, but the best way to get it is to imagine stacking up cans row-by-row until you get to the other end.
    • The second type is pretty simple: imagine a square on a grid and you mark each dot around the edge, from bottom-left to bottom-right, from there to top-right, from there to top-left, and back down to bottom-left. This is exactly how the loops work here.
  • After all that it just returns the coords variable with its appended data from the loops.

 

After all that is mostly developer-defined stuff, such as areas and single objects. The developer can also create functions which would be called by the checkLoc function. It is all very easily extended and built upon.