Please see Piazza, and the course webpage for the deadlines of each homework. If there are any ambiguities about the homeworks, please ask on Piazza.
Please click on the homework sections below to see the contents.
This homework has two parts. Each will be implemented in a separate file as a separate class.
First, you will implement a class called CoordinateConversion (in a CoordinateConversion.java file). This class will include a method int coordConversion(double x, double minCoord, double maxCoord, int pixelSize). You cannot change the signature for the method. This method must be public static. This method is similar to the ones we've discussed in lab, and will convert between a point (x) within a bounding coordinate plane bounded by minCoord as the minimum coordinate value, and maxCoord is the maximum coordinate value. The method must determine which pixel should represent that point within a screen of a given pixelSize. That coordinate within the screen is returned. Recall that this is the problem we need to solve for OpenMaps where we have a bounding box and a point within it, and we need to figure out where to draw that point on the screen. Note that your method is only dealing with a single dimension (x or y/longitude or latitude). For example, if we have a bounds on the coordinates between 5 and 15, we're trying to plot a point at 10, and we're plotting it on a screen that is 800 pixels wide, we want to plot it at 400 pixels. So, coordConversion(10, 5, 15, 800) == 400. Please see the assertions below for more details.
Error Checking: Your implementation must include error checking. If x is outside of the maximum and minimum boundaries, it must treat x as if it is the minimum boundary, or the maximum boundary, depending on if it is larger than, or less than the bounds, respectively. If the minimum coordinate is greater than, or equal to the maximum coordinate, or if the pixel size is not positive (i.e. if it is <= 0), your implementation must return -1 to indicate an error due to invalid input.
Example Assertions: We include a number of assertions that your implementation must past below. In the future, we might not include all of the assertions, instead relying on you to test your program thoroughly yourself.
// Error cases assert coordConversion(5, 10, 15, 800) == 0 : "5 in 10x15 to 800px should be 0"; assert coordConversion(20, 10, 15, 800) == 800 : "20 in 10x15 to 800px should be 800"; assert coordConversion(10, 15, 10, 800) == -1 : "10 in 15x10 to 800px should be -1"; assert coordConversion(10, 10, 15, 0) == -1 : "10 in 10x15 to 0px should be -1"; assert coordConversion(10, 10, 15, -800) == -1 : "10 in 10x15 to -800px should be -1"; // Edge cases assert coordConversion(5, 5, 15, 5) == 0 : "5 in 5x15 to 5px should be 0"; assert coordConversion(15, 5, 15, 5) == 5 : "15 in 5x15 to 5px should be 5"; assert coordConversion(15, 0, 300, 300) == 15 : "15 in 0x300 to 300px should be 15"; // Correctness tests assert coordConversion(30, 0, 300, 200) == 20 : "30 in 0x300 to 200px should be 20"; assert coordConversion(130, 100, 400, 200) == 20 : "130 in 100x400 to 200px should be 20"; assert coordConversion(10, 5, 15, 800) == 400 : "10 in 5x15 to 800px should be 400";
Second, you'll implement a program that emulates some of the logic in 2048. You will implement a Combine class (in a Combine.java file) with a number of methods specified below. First, have a look at and play a few games of 2048 to get an idea of what we're eventually going to be shooting for. 2048 can be a little like a drug addiction, so be sure to pry yourself away, and back to this homework. We aren't at the level yet where all of it can be implemented, but you'll implement the shuffling left of blocks with the collapsing of two blocks of like values together into a single block of double the value.
We will represent a single row of the 2048 square that includes only three blocks with a 3-length string. Each character in the string is either a '4', a '2', or a '_' which designates a "blank" space. Example rows are "42_", "4_4", and "242". Your program will execute a "shift blocks left" operation which will include combining like blocks into one of double the value. Note that newly created (double valued) blocks are not combined with other blocks. Examples of proper shift left operations include:
Note that for this homework, you cannot use loops. We haven't learned them yet, and you should be able to complete the assignment with only concepts we've learned so far.
Error Checking: Your code must handle quite a bit of error checking. The strings being passed in must:
You will implement four methods:
Example Assertions:
assert validateChar('2') : "2 should be a valid char"; assert validateChar('4') : "4 should be a valid char"; assert validateChar('_') : "_ should be a valid char"; assert !validateChar(' ') : "space should not be a valid char"; assert !validateChar('3') : "3 should not be a valid char"; assert !validateRow("2222") : "2222 should not be valid"; assert !validateRow("__") : "__ should not be valid"; assert !validateRow("aaa") : "aaa should not be valid"; assert !validateRow("333") : "333 should not be valid"; assert validateRow("22_") : "22_ should be valid"; assert validateRow("_2_") : "_2_ should be valid"; assert validateRow("242") : "242 should be valid"; assert "4__".equals(moveLeft("__4")) : "__4 doesn't change to 4__"; assert "4__".equals(moveLeft("_4_")) : "_4_ doesn't change to 4__"; assert "42_".equals(moveLeft("4_2")) : "4_2 doesn't change to 42_"; assert "4__".equals(combineLeft("__4")) : "__4 doesn't change to 4__"; assert "8__".equals(combineLeft("_44")) : "_44 doesn't change to 8__"; assert "4__".equals(combineLeft("2_2")) : "2_2 doesn't change to 4__"; assert "4__".equals(combineLeft("22_")) : "22_ doesn't change to 4__"; assert "42_".equals(combineLeft("222")) : "222 doesn't change to 42_"; assert "44_".equals(combineLeft("422")) : "422 doesn't change to 44_"; assert "242".equals(combineLeft("242")) : "242 doesn't change to 242"; assert "8__".equals(combineLeft(combineLeft("422"))) : "Double invocation doesn't work!"; // You should be using your validate methods to check for erroneous inputs! assert "_222".equals(combineLeft("_222")) : "2222 should be invalid!"; assert "333".equals(combineLeft("333")) : "333 should be invalid!"; assert "__".equals(combineLeft("__")) : "__ should be invalid!";
Notes and grading: Your implementations must compile to get any credit. Please develop these in small chunks. Don't program everything, and hope it will work. Write each method separately, and test it separately. Your implementation will get credit proportional to how many assertions they pass. The methods they implement must be public static, and have the specified signatures/prototypes to get any credit. Your main method will not be invoked, so do not assume that it executes. Make sure to submit your .java file, and that it has the correct class name.
If you simply implement your methods in such a way that they are customized to the provided specific test cases (i.e. by returning the desired string, but not having any of the logic required by the assignment), you'll receive no credit.
Submission: Please submit both .java files via blackboard.
This homework has two parts. Each will be implemented in a separate file as a separate class. Submit only the two .java files you complete.
Implement a few methods to do some mathematical computations. You'll create a HazMaths class in a corresponding .java file. These should have the following definitions:
assert isPrime(2); assert isPrime(53); assert !isPrime(55); assert !isPrime(24); assert !isPrime(-37337);Prime numbers form the basis of cryptography! Read into why this is a little bit. Really cool stuff.
assert sumOfSums(1) == 1; assert sumOfSums(3) == 10; assert sumOfSums(6) == 56; assert sumOfSums(25) == 2925; assert sumOfSums(-5) == 0;
Similar to in HW1, you'll implement a left shift of decimals in a string, with combining of multiple like digits into a single digit of double the value. The main difference between HW1 and this, is that now the string representing a row in 2048 can be of any length! You'll implement a Combine class in a comparable .java file.
As before, the input string can only include the characters '_', '2', and '4'. Unlike before, it can be of any length (including length 0). Any '2's that have no other characters, or any number of '_'s between them combine to become a '4' (i.e. two '2's disappear, and a '4' is left in one of their space). Likewise, '4's become '8's. Any digit that is the result of a combination cannot be combined with another digit. All digits are combined in this way, and shifted to the far left so that any '_' appear on the right of the string. The length of the string remains unchanged.
This functionality is implemented across multiple methods that you must implement.
You must invoke the validateRow method to test if the input String is valid. If it is not, return the input string directly without change.
It is highly suggested that you use the moveLeft method to help you with this implementation. When generating your new string, it is much easier to be able to ignore all '_' between digits.
You must invoke the validateRow method to test if the input String is valid. If it is not, return the input string directly without change.
assert validateChar('_'); assert !validateChar(' '); assert validateRow("2222"); assert validateRow("_24_"); assert !validateRow("2234_"); assert validateRow(""); assert !validateRow("*"); assert "***".equals(repeat('*', 3)); assert "".equals(repeat('*', 0)); assert "44444444".equals(repeat('4', 8)); assert "4".equals(eliminateUnderscores("__4__")); assert "244".equals(eliminateUnderscores("2_4_4_")); assert "".equals(eliminateUnderscores("___")); assert "242442".equals(eliminateUnderscores("242442")); assert "4____".equals(moveLeft("__4__")); assert "244___".equals(moveLeft("2_4_4_")); assert "___".equals(moveLeft("___")); assert "_3_".equals(moveLeft("_3_")); assert "242442".equals(moveLeft("242442")); assert "484___".equals(combineLeft("224422")); assert "484________".equals(combineLeft("2_2_4_4_2_2")); assert "242424__".equals(combineLeft("242_42_4")); assert "828____".equals(combineLeft("__44244")); assert "".equals(combineLeft("")); assert "22344".equals(combineLeft("22344")); assert "88__________".equals(combineLeft(combineLeft("_2_22_222_4_")));
Please reread the "course philosophies" on the main course's webpage. You always want to implement and test the smallest chunk of code you can. If you try and write the whole program, and then start debugging/testing, your homeworks will take a ton of time. I'm breaking up these homeworks into separate methods explicitly so that you can implement the methods one by one, and test them before moving on to the next. If you implement a method, and test it (so you have confidence it works), then you should think "this method provides me the functionality to do X" for whatever X the method is implemented to do. Now implementing the next methods that might use that method are easier to think about because if you need that functionality X, then you can just invoke the method! Easy-peasy. Once you have the repeat method done, when you need to generate a number of '_', you don't need to think about a loop, only that you need to invoke that method! This is abstraction.
You know variables, conditionals, loops, math, and methods. Those are the building blocks for every single program that is written! With practice, you'll be able to master these building blocks, and create awesome programs. But if the core concepts for all programming can be learned in a single semester, what are you possibly going to learn in subsequent CS classes??? Put another way, what do you think defines a "good" software developer from one that is not?
Programs very quickly become too complicated for even a good programmer to understand. Our short-term memory holds 7 ± 2 items. Every conditional, variable, and loop takes up one of those! No wonder we can't keep the whole program in our heads!!! "Good" programmers, then are good at using abstraction to hide complexity. Methods are the main tool we have right now for abstraction. A method hides its own, possibly complex, functionality behind an method name, a return value, and a set of arguments. You just need to invoke the method to harness its power, and forget about all the details that would use up those 7 ± 2 slots: abstraction! The best programmers always seek out abstraction to make it easier to understand complicated programs.
It will be difficult for you to understand at this point when to use abstraction, or even how it can be helpful. As you become more familiar with coding, and as you get to the point when it all doesn't feel quite so foreign (with hard work, you'll get there!), you'll start to get a good understand of how to use methods and abstractions. For now, hold in there, and try and heed this advice on how to write your programs methodically! It's only a matter of time and sweat till you're a master of abstraction and all things programming!
Notes and grading: Your implementations must compile to get any credit. Please develop these in small chunks. Don't program everything, and hope it will work. Write each method separately, and test it separately. Your implementation will get credit proportional to how many assertions they pass. The methods they implement must be public static, and have the specified signatures/prototypes to get any credit. Make sure to submit your .java file, and that it has the correct class name. Your main method will not be invoked, so do not assume that it executes.
If you simply implement your methods in such a way that they are customized to the specific test cases (i.e. by returning the desired string, but not having any of the logic required by the assignment), you'll receive no credit.
Submission: Please submit both .java files via blackboard.
This homework has two parts. Each will be implemented in a separate file as a separate class. Submit only the two .java files you complete.
As you've seen in many labs, open street maps is a wonderful resource! Not only can you browse geographically, but you can also download the data that backs the maps. As we're going to implement our own version of a mapping application, we need to figure out how to understand the data that is so diligently provided to us by open street maps. As a step toward providing our own mapping application, we will start parsing the .osm file. You can read about .osm files, and specifically the nodes within them. Read a little bit about the format to get a grip on it, and try and answer the questions:
For this assignment, you'll implement a class called OSMParse in a corresponding OSMParse.java file. This implementation will be the basis for your mapping application. If you look at the osm format, it nests different types of items inside of each other just like java nests conditionals, loops, and methods inside of {...}. Examples of these items of the .osm file include:
You must implement the following methods. Please reference a simple test file that you'll be parsing through with these methods. You must understand the format to some degree to understand these methods. Also, you will be given a .java file (below) that will open a .osm file and return the array of Strings (the String[] osm below).
I strongly recommend that you use the nthEntry method to get the bounds item, and the getAttribute method to find the values for maxlon, maxlat, minlon, and minlat. You will also want to look up the Double class in the javadocs, and find a way to take a string, and produce a double.
I strongly suggest that you use your numEntries method so that you know how many entries you can loop through, nthEntry to get the desired idx, and getAttribute to get the longitude, latitude, and node identifier.
Testing: Please see the OSMParse.java file. You can base your implementation on this. It includes a method called getOsmData that you can use to read in a .osm file into our format. We provide two test .osm files: a simple test file, and a file that includes SEAS at GWU.
Your own 2048 is edging closer to reality! Now we'll implement much of the functionality you already have, with arrays of integers instead of strings of digits. This will enable us to, among other things, go up to numbers greater than 8! You will implement a class called OneDimensional2048 in a OneDimensional2048.java file. You must implement a number of familiar methods:
You must invoke the validateRow method to test if the input array of integers is valid. If it is not, return false. True otherwise.
Some assertions you can use to test your code. Note that for these assertions to work, you'll need to implement a method called identicalRows, (boolean identicalRows(int[] testRow, row))) that compares the passed in row against the first argument. If the contents are the same, it returns true. Otherwise, false.
int[] row; assert(!validateValue(8, 4)); assert(validateValue(8, 8)); assert(validateValue(8, 16)); assert(validateValue(0, 16)); assert(validateValue(2, 2048)); assert(!validateValue(7, 2048)); assert(!validateValue(1023, 2048)); assert(!validateValue(1025, 2048)); assert(validateRow(new int[]{2, 2, 2, 2})); assert(validateRow(new int[]{0, 2, 4, 0, 32})); assert(!validateRow(new int[]{2, 2, 0, 3, 4, 0})); assert(validateRow(new int[]{})); assert(!validateRow(new int[]{8, 2, 64, 32, 30})); row = new int[]{0,0,4,0,0}; assert(moveLeft(row) && identicalRows(new int[]{4,0,0,0,0}, row)); row = new int[]{0,0,4,0,0}; assert(moveLeft(row) && !identicalRows(new int[]{4,0,0,0,0,0}, row)); row = new int[]{2,0,4,0,0,16}; assert(moveLeft(row) && identicalRows(new int[]{2,4,16,0,0,0}, row)); row = new int[]{0,0,0}; assert(moveLeft(row) && identicalRows(new int[]{0,0,0}, row)); assert(!moveLeft(new int[]{2,0,31})); row = new int[]{4,16,2048}; assert(moveLeft(row) && identicalRows(new int[]{4,16,2048}, row)); row = new int[]{8,8,16,16,32,32}; assert(combineLeft(row) && identicalRows(new int[]{16,32,64,0,0,0}, row)); row = new int[]{2,0,2,8,0,8,64,0,64,0}; assert(combineLeft(row) && identicalRows(new int[]{4,16,128,0,0,0,0,0,0,0}, row)); row = new int[]{2,0,8,2,0,64,4,0,64,0}; assert(combineLeft(row) && identicalRows(new int[]{2,8,2,64,4,64,0,0,0,0}, row)); row = new int[]{2,0,8,2,0,64,4,0,64,0}; assert(combineLeft(row) && identicalRows(new int[]{2,8,2,64,4,64,0,0,0,0}, row)); row = new int[]{0,0,2,2,128,64,0,64}; assert(combineLeft(row) && identicalRows(new int[]{4,128,128,0,0,0,0,0}, row)); row = new int[]{0,0,2,2,128,1234,64,0,64}; assert(!combineLeft(row)); row = new int[]{}; assert(combineLeft(row) && identicalRows(new int[]{}, row)); row = new int[]{0,1024,512,256,128,64,32,16,8,4,2,0,2,0}; assert(combineLeft(row) && combineLeft(row) && combineLeft(row) && combineLeft(row) && combineLeft(row) && combineLeft(row) && combineLeft(row) && combineLeft(row) && combineLeft(row) && combineLeft(row) && identicalRows(new int[]{2048,0,0,0,0,0,0,0,0,0,0,0,0,0}, row));
Notes and grading: Your implementations must compile to get any credit. You must include all of the required methods, and they must compile, even if they don't work. Please develop these in small chunks. Don't program everything, and hope it will work. Write each method separately, and test it separately. Your implementation will get credit proportional to how many assertions they pass. The methods they implement must be public static, and have the specified signatures/prototypes to get any credit. Make sure to submit your .java file, and that it has the correct class name. Your main method will not be invoked, so do not assume that it executes.
If you simply implement your methods in such a way that they are customized to the specific test cases we provide (i.e. by returning the desired string, but not having any of the logic required by the assignment), you'll receive no credit.
Submission: Please submit both .java files via blackboard.
The next step is to finish a playable version of 2048! Before you read the specification, and the set of methods, please think through how you would design this program given what you've implemented so far.
Summary: This assignment will break the problem of providing a 2048 playable environment up into a few pieces:
You'll implement a TwoDimensional2048 class in a comparably named file. It will include the following methods:
OneDimensional2048.validateRow(row);Additionally, this method checks that each row is of the same length. Note that it does allow boards that are not square.
OneDimensional2048.combineLeft(row);Your previous implementation has to be in the same directory/folder as your current implementation. Though you don't have to do this, I strongly recommend it. You already did the hard work for combine; you might as well use it!
Other classes, and provided files: We are providing a class with assertions and some methods, and the Rnd2048.java class. You should base your implementation off of these. To get the assertions to work, you'll have to implement many of the methods above.
You will have to use methods from another class we provide to get both random values (e.g. 2 or 4) to insert into the 2048 board, and to give us an offset into the blank (empty) spaces into the board to insert a new value.
int value = Rnd2048.randValue(); int offset = Rnd2048.randNum(numUnoccupied(b))
Note that it is very important for this assignment that we don't actually use random numbers. It would be difficult to test such a solution. Thus we provide the Rnd2048 class for your use. It is required to get the provided assertions to work. Please note that the assertions assume that you only call each of these random methods when required. If you call them additional times, then they might start giving values that will make the assertions fail. Think of both of these methods as returning a value that is at an offset into an array that increases by one every time you call it.
Notes and grading: Your implementations must compile to get any credit. You must include all of the required methods, and they must compile, even if they don't work. Please develop these in small chunks. Don't program everything, and hope it will work. Write each method separately, and test it separately. Your implementation will get credit proportional to how many assertions they pass. The methods they implement must be public static, and have the specified signatures/prototypes to get any credit. Make sure to submit your .java files, and that TwoDimensional2048.java has the correct class name. Your main method will not be invoked, so do not assume that it executes.
If you simply implement your methods in such a way that they are customized to the specific test cases we provide (i.e. by returning the desired string, but not having any of the logic required by the assignment), you'll receive no credit.
Submission: Please submit your .java files (if you use your code for the previous assignment, please submit it as well) via blackboard.
In this homework, you will improve your GWMaps application to include information about traffic signals, and roads. You will also break your implementation into separate classes, and make it object oriented. The high-level idea is that you'll implement a number of classes:
This homework should be completed in two phases. First, implement the OSMNode and OSMRoad classes, and test them. Second, implement the GWMap class which will include the more advanced parsing of the .osm file that uses the previous two classes to represent the data.
Provided files: Find the GWMapMain.java file, and two test files, OSMTest.osm and SEASatGWU.osm. The former is simplified, and includes much simpler data, while the latter includes the raw .osm output from Open Street Maps.
You must understand the tests, and the methods before starting to write code. Use the assertions as a guide, but you must implement all methods correctly (i.e. abiding by the specification).
The public methods you must implement for your OSMNode class include the following. Node that you can include any number of private methods for your own use. All methods, unless otherwise specified are not static.
The public methods you must implement for the OSMRoad class include the following. Again, you can include any number of private methods, and the following are not static.
The GWMap class is the main class that is to be used by developers using our map. Objects of it can be created, one per .osm file. The following methods are required in it, and are public and not static.
A number of private methods might be helpful within your GWMap class (they were for me!). These include:
Each of these methods are pretty complicated, and include all of the parsing work done within this homework. They translate the .osm file into a set of nodes and roads that can be easily used by clients of your class.
Parsing the .osm file. Here we describe which of the nodes is a traffic signal, and how to find the roads within the .osm file.
<node id="291675382" visible="true" version="3" changeset="5155510" timestamp="2010-07-07T01:34:45Z" user="aude" uid="12055" lat="38.8992236" lon="-77.0488323"/>The node's identifier is 291675382.
<node id="291675382" visible="true" version="3" changeset="5155510" timestamp="2010-07-07T01:34:45Z" user="aude" uid="12055" lat="38.8992236" lon="-77.0488323"/> <node id="49824719" visible="true" version="7" changeset="3920604" timestamp="2010-02-20T06:15:27Z" user="NE2" uid="207745" lat="38.9020773" lon="-77.0488070"> <tag k="highway" v="traffic_signals"/> </node>
<way id="6056057" visible="true" version="14" changeset="19460319" timestamp="2013-12-15T08:51:55Z" user="michael colvin" uid="1329572"> <nd ref="49777749"/> <nd ref="291675380"/> <nd ref="49777696"/> <nd ref="49777690"/> <nd ref="49741695"/> <nd ref="2383566163"/> <tag k="HFCS" v="Collector"/> <tag k="highway" v="residential"/> <tag k="name" v="H Street Northwest"/> <tag k="source:HFCS" v="District of Columbia (DC GIS)"/> <tag k="tiger:cfcc" v="A41"/> <tag k="tiger:county" v="District of Columbia, DC"/> <tag k="tiger:name_base" v="H"/> <tag k="tiger:name_direction_suffix" v="NW"/> <tag k="tiger:name_type" v="St"/> <tag k="tiger:reviewed" v="no"/> <tag k="tiger:zip_left" v="20037"/> <tag k="tiger:zip_right" v="20037"/> </way>
Notes and grading: Your implementations must compile to get any credit. You must submit at least GWMap.java, OSMNode.java, and OSMRoad.java. You must also submit any other .java files you use. You must include all of the required methods, and they must compile, even if they don't work. Please develop these in small chunks. Don't program everything, and hope it will work. Write each method separately, and test it separately. Your implementation will get credit proportional to how many assertions they pass. Any main methods you use will not be invoked, so do not assume that it executes.
If you simply implement your methods in such a way that they are customized to the specific test cases we provide (i.e. by returning the desired string, but not having any of the logic required by the assignment), you'll receive no credit.
Submission: Please submit your .java files (if you use your code for the previous assignments, please submit it as well) via blackboard.
2048 is too exhausting to play on our own. So many moves. So many numbers. To remedy this situation, in this homework you'll implement an AI to automatically play 2048 for you. This will consist of two phases:
Object Oriented 2048
In this part of the homework, you're going to create a class called TwoThousandFourtyEight (in a TwoThousandFourtyEight.java file) that allows you to make 2048 objects that each contain a 2048 board, that can be played. This class must implement the following methods:
In addition to these, you can implement as many private methods as you want.
To test your implementation, find the provided Main2048.java and Rnd2048.java files. Note that for this homework, you want to make sure that you don't modify Rnd2048.java.
I highly suggest that you use your previous implementations of 2048 for most of the logic and board management. Any files that you do use, you must submit. We will use our own Rnd2048, but please submit the one you use regardless.
2048 AI
Time to let the machines rule the world! You must complete the playRandom and playAi methods in the Ai2048 class in the provided Ai2048.java file. In that file, you'll find a very dumb AI implemented already that simply moves the board left until the game is over. The AiMain2048.java file implements a main to run these different AI implementations many times, and prints out the average score and maximum tile value. This will let you test your AI implementations, and let you know how you're doing! Your implementation of these methods will use the Object Oriented implementation of 2048 from the previous section.
The playRandom method in Ai2048 simply randomly chooses if it should swipe up, down, left, or right. This is, in some sense, a base-line that you can use to measure how good your implementation is! Can you do better than rolling a dice? Your implementation of playRandom should be able to get a score of around 350 points with an average maximum tile of around 73. To get credit for this method, your implementation must achieve between 300 and 400 points.
Your playAI method must be more creative. To get credit for this method, it must get over 400 points on average. A very simple implementation (that is around 3 lines of code) can achieve around 840 points, so you don't need to get too complex here. However, it will take some critical thought to figure out a strategy for playing 2048.
Please submit your Ai2048.java file, and any others that you require for it to work. However, we will be using our own implementation of TwoThousandFourtyEight.java to prevent anyone cheating in that implementation. If you do not submit any required file, your implementation will not compile, and you will not receive credit.
Execution time limits. Your implementation of your AI must not take longer than 5 minutes to execute the AiMain2048.java main method. We must put an arbitrary limit on execution to be able to detect infinite loops.
AI Face-Off
The above instructions are part of the required homework. In addition to this, you can complete an optional implementation of your AI (still in the playAI method) that is significantly more intelligent. There is no minimum required score for you to achieve. Instead, your AI will compete with those of your classmates. What follows is a set of deadlines. At each of these deadlines, we will run a competition between all AIs that have been submitted for that deadline. At least the top five implementations will receive extra credit. In subsequent competitions, the same students cannot receive more extra credit, with one exception: the last deadline is open for anyone to compete in, regardless if they've been at the top in a previous competition. If you provide an implementation that beats 1250 points (Chester's implementation), extra points to you!
Note: The execution time limits for this competition are extended to 10 minutes.
The deadlines for these competitions follow:
There will be separate submission links on blackboard for each deadline. Deadlines are at midnight EST. Please submit all .java files required to execute your solution. This must include TwoThousandFourtyEight.java and any supporting files.
In this homework, you'll expand your Maps application to provide directions! Your implementation will have the following components:
The directions consist of three components:
Algorithm for finding directions. For simplicity your code for finding the directions, they must be found in a very specific manner that is, in Computer Science, called a greedy algorithm. We start at OSMNode A. Of all of the nodes that are adjacent to that node on any roads, the next node we move to is the one that is closest (in terms of distance as the bird flies) to the goal (OSMNode B). This process is repeated, by always making the next move toward the destination until we are either at the destination, or no adjacent node is closer than the current one, in which case, we return null.
This implementation requires a few "support" methods in the GWDirections class. As always, these must have the exact prototypes as below. These include:
To test your program, the GWDirectionsMain class uses the OSMTest.osm and SEASatGWU.osm files.
One way to test your program, is to visualize your roads and directions. Find the GWMapDraw.java program to help you with that. A sample output with a working program is on the right that displays the SEASatGWU.osm file. Note that you will have to get most of your implementation working to be able to use this, but it simply will output all of the road's nodes (using methods from hw5), and will print out an array of nodes as the magenta and red path. This will help you visualize where your directions are going, and perhaps help you debug.
Please feel free to use this program to help you debug, and modify it as you wish. Please do not submit this file. We will not use it in evaluating your program, and it is only to help debugging.
Notes and grading: Your implementations must compile to get any credit. You must submit at least GWDirections.java and GWDirectionsMain.java (though we will use our own GWDirectionsMain.java). You can optionally submit your GWMap.java, OSMNode.java, and OSMRoad.java if you wish. Submit all files that you require for your program to work. You must include all of the required methods, and they must compile, even if they don't work. Code that doesn't compile will receive zero credit. Please develop the implementation in small chunks. Get the first methods to work before the last. Don't program everything, and hope it will work. Write each method separately, and test it separately. Your implementation will get credit in some manner proportional to how many assertions they pass. Any main methods you use will not be invoked, so do not assume that it executes.
If you simply implement your methods in such a way that they are customized to the specific test cases we provide (i.e. by returning the desired string, but not having any of the logic required by the assignment), you'll receive no credit.
Submission: Please submit your .java files (if you use your code for the previous assignments, please submit it as well) via blackboard.