Battlesnake Challenge #1 - Python
Tags: programming, challenge, python
Published: 2024-05-15 10:00:00

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](https://dev.to/robvanderleek/battlesnake-challenge-1gkf) for a short intro to this series.

You can also follow my progress [on GitHub](https://github.com/getcodelimit/battlesnake-challenge).

## Python

For the first post in this series I picked an easy start: Python.

Python is a beautiful language. Readability was one of the language’s core design principles, and that feature still makes Python stand out from other contemporary programming languages. Open a Python project, any Python project, and the code immediately has a familiar feel to it.

Also, the [Python Standard Library](https://docs.python.org/3/library/index.html) is very versatile, the language comes with batteries included for many things.

Let's see how these language features help in building Battlesnakes...

## Hello, world!

The obligatory "Hello, world!" does not become more idiomatic than it looks in Python:

```python
print("Hello, world!")
```

This is the Dockerfile for the runtime environment:

```docker
FROM python:3.11
RUN mkdir /app
WORKDIR /app
COPY snake.py .
CMD ["python", "snake.py"]
```

And here's the development setup in action:

{% asciinema https://asciinema.org/a/659374 %}

## A basic web server

Python comes with a simple [HTTPServer](https://docs.python.org/3/library/http.server.html) as part of its Standard Library. There's a threaded and a non-threaded version. For my implementation, the non-threaded server will do.

This is the full code for the web server that implements the `GET /` endpoint:

```python
import os
import json
from http.server import HTTPServer, BaseHTTPRequestHandler

class RequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        handle_get_meta_data(self)

def handle_get_meta_data(request_handler):
    content = json.dumps({
        'apiversion': '1',
        'author': 'robvanderleek',
        'version': '1.0',
        'color': '#3776ab',
        'head': 'safe',
        'tail': 'sharp'
    })
    request_handler.send_response(200)
    request_handler.end_headers()
    request_handler.wfile.write(content.encode('utf-8'))

PORT=int(os.getenv('PORT', 3000))

print(f'Starting Battlesnake server on port: {PORT}')
server = HTTPServer(('0.0.0.0', PORT), RequestHandler)
server.serve_forever()
```

## Game logic

The game logic is spread out over a number of short, and IMHO very readable Python functions.

Below is one of the core game logic functions that returns a prioritized list of directions based on the position of the snake's head and the position of the nearest food on the board:

```python
def preferred_directions(board, head):
    food = nearest_food(head, board['food'])
    result = []
    if head['x'] != food['x']:
        result.append('right' if head['x'] < food['x'] else 'left')
    if head['y'] != food['y']:
        result.append('up' if head['y'] < food['y'] else 'down')
    for d in ['right', 'down', 'left', 'up']:
        if not d in result:
            result.append(d)
    return result
```

And this is the complete code in action:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ssawhetq6gkmq3bmdzuf.gif)

The full code for the Python Battlesnake can be found [here on GitHub](https://github.com/getcodelimit/battlesnake-challenge/blob/main/python/).

## Feedback appreciated!

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!