In this series I'll share my progress with my self-imposed programming challenge: build a Battlesnake in as many different programming languages as possible.
Check the first post for a short intro to this series.
You can also follow my progress on GitHub.
Java is the language of Enterprises, the business logic of many large back-office systems is written in it.
I've written a lot of Java code in the past, but Python and JavaScript have taken its place in my contemporary programming activities.
Because Java can be used to write very readable and robust software (Java IDEs tend to have great refactoring support), I still feel it's the right language for some systems.
Compared to its predecessors, Java brought developers a lot of improvements (depending on your taste, of course): automatic memory management, built-in collection types, and an extensive standard library. However, the language is now over 30 years old, and there are some clear signs of the times, such as no JSON support in the standard library (but it does have XML support ?).
Can Java, as it comes out-of-the-box today, still be used to build a clean and concise Battlesnake implementation? Read along to find out.
This is how Snake.java looks:
public class Snake { public static void main(String args[]) { System.out.println("Hello world!"); } }
This is how the Dockerfile looks:
FROM eclipse-temurin:17-jdk RUN mkdir /app WORKDIR /app COPY Snake.java . RUN javac Snake.java CMD ["java", "Snake"]
And here's the development setup in action:
To be honest, I had to Google the availability of a basic web server in the Java standard library. It turns out there's an HTTP server in (based on the package name) what is probably one of the oldest parts of the standard library: com.sun.net.httpserver.HttpServer.
Using the server implementation is actually quite straightforward, here's my initial code to handle the Battlesnake metadata request:
import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpExchange; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; public class Snake { static class BattleSnakeHandler implements HttpHandler { public void handle(HttpExchange exchange) throws IOException { String response = "{\"apiversion\": \"1\", " + "\"author\": \"'robvanderleek\", \"version\": \"1.0\", " + "\"color\": \"#b07219\", \"head\": \"safe\", " + "\"tail\": \"sharp\"}"; exchange.sendResponseHeaders(200, response.length()); OutputStream os = exchange.getResponseBody(); os.write(response.getBytes()); os.close(); } } public static void main(String args[]) throws IOException { int port = Integer.parseInt( System.getenv().getOrDefault("PORT", "3000")); HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); server.createContext("/", new BattleSnakeHandler()); server.setExecutor(null); server.start(); System.out.println( String.format("Starting Battlesnake server on port: %d", port)); } }
A significant part of the game logic code is there to parse the incoming JSON data. The standard Java library does not contain a JSON parser, and a typical parser library contains thousands of lines of code.
With a lot of hacks I was able to parse the Battlesnake JSON, and only that JSON
Below are four of the functions in the code related to JSON parsing (these functions parse fields, objects, and arrays):
private String getField(String json, String name) { String needle = '"' + name + '"'; return json.substring(json.indexOf(needle) + needle.length() + 1); } private String getBalanced(String json, String name, char open, char close) { String start = getField(json, name); int idx = 0, indent = 0; do { if (start.charAt(idx) == open) { indent++; } else if (start.charAt(idx) == close) { indent--; } idx++; } while (indent > 0); return start.substring(0, idx); } private String getObject(String json, String name) { return getBalanced(json, name, '{', '}'); } private String getArray(String json, String name) { return getBalanced(json, name, '[', ']'); }
The remainder of the game logic is quite straightforward, I used a basic Coordinate class for better readability and conciseness:
private Coordinate nearestFood(String board, Coordinate head) { String foodJson = getArray(board, "food"); Set<Coordinate> food = getCoordinates(foodJson); double distance = Double.MAX_VALUE; int x = 255, y = 255; for (Coordinate f: food) { double d = Math.sqrt(Math.pow(head.x - f.x, 2) + Math.pow(head.y - f.y, 2)); if (d < distance) { distance = d; x = f.x; y = f.y; } } return new Coordinate(x, y); }
I'm sure the game logic can be improved, why not give it a try? ?
And this is the complete code in action:
The full code for the C Battlesnake can be found here on GitHub.
I hope you like reading along with my coding adventures.
Let me know in the comments below what you think about the code above, or what programming languages you are looking forward to in this series.
Until the next language!
The above is the detailed content of Battlesnake Challenge # Java. For more information, please follow other related articles on the PHP Chinese website!