Initial commit for the Python version

This commit is contained in:
Gergely Polonkai 2017-06-12 10:56:08 +02:00
commit 7415f825ef
7 changed files with 272 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.pyc
__pycache__/
/.venv/
/.coverage

32
data/plane.erodar.txt Normal file
View File

@ -0,0 +1,32 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~===~===~~~~~~~~=~~~~~~~~~
~~~~~~====~~==~~~~~~~=~~~~~~~~~~
~~~~~=====#=======~~~=~~~~~~~~~~
~~~~=====#======~==~===~~~~~~~~~
~~~=======#==============~~~~~~~
~~=========#==============~~~~~~
~~~=========#==============~~~~~
~~===========#==============~~~~
~~~===========#======~=======~~~
~~~=======####==============~~~~
~~~~======#================~~~~~
~~~~~=====#=====~========~~~~~~~
~~~~~~~====#===~~====~==~~~~~~~~
~~~~~~~~==#===~~~~===~~==~~~~~~~
~~~~~~~===#=~~~~~~~~===~=~~~~~~~
~~~~~~===#===~~~~~~====~~~~~~~~~
~~~~~~~~=#====~~~~~~~~~~~~~~~~~~
~~~~~~~~==#==~~~~~~~=~~~~~~~~~~~
~~~~~~~~~=#=~~~~~~~==~~~~~~~~~~~
~~~~~~~~~===~~~~~~~~~~~~~~~~~~~~
~~~~~~~~====~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~====~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~===~~~~~~~~~~~~~~~~~~~
~~~~~~~~~=====~~~~~~~~~~~~~~~~~~
~~~~~~~~~~===~~~~~~~=~~~~~~~~~~~
~~~~~~~~~~~==~~~~~~==~~~~~~~~~~~
~~~~~~~~~~==~~~~~~=~==~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

23
data/terrain.json Normal file
View File

@ -0,0 +1,23 @@
{
"water": {
"icon": "~",
"map_char": "~",
"color16": 12,
"color256": 57,
"color": "#0000bb"
},
"field": {
"icon": "=",
"map_char": "=",
"color16": 11,
"color256": 228,
"color": "#bbbb00"
},
"road": {
"icon": "#",
"map_char": "#",
"color16": 8,
"color256": 244,
"color": "#808080"
}
}

0
wmud/__init__.py Normal file
View File

8
wmud/__main__.py Normal file
View File

@ -0,0 +1,8 @@
from wmud.world.map import Plane, load_terrain
load_terrain('data/terrain.json')
map = Plane()
map.read('data/plane.erodar.txt')
print(map)
print('')
map.print((0, 0), 11)

30
wmud/world/__init__.py Normal file
View File

@ -0,0 +1,30 @@
"""World definitions for wMUD
"""
from enum import IntEnum
class Directions(IntEnum):
"""All the available directions
"""
NORTH = 0
SOUTH = 1
EAST = 2
WEST = 3
NORTH_EAST = 4
SOUTH_WEST = 5
NORTH_WEST = 6
SOUTH_EAST = 7
UP = 8
DOWN = 9
@property
def opposite(self):
"""Get the opposite direction
"""
if self % 2 == 0:
return self.__class__(self + 1)
return self.__class__(self - 1)

175
wmud/world/map.py Normal file
View File

@ -0,0 +1,175 @@
import json
from math import sqrt
TYPES = {}
class TileType(object):
def __init__(self, data):
self.map_char = data.pop('map_char')
self.extra_data = data
def __str__(self):
return self.map_char
class Coordinate(object):
def __init__(self, x, y):
if x < 0 or y < 0:
raise ValueError(f'Invalid coordinates [{x}; {y}]')
self.__x = x
self.__y = y
@property
def x(self):
return self.__x
@property
def y(self):
return self.__y
def __str__(self):
return f'[{self.x}; {self.y}]'
class Tile(object):
def __init__(self, type):
self.__type = type
def __str__(self):
return self.__type.char
class Plane(object):
def __init__(self):
self.__tiles = {}
self.width = None
self.height = 0
def read(self, filename):
with open(filename) as f:
fields = f.read().split()
self.width = None
for row_num, row in enumerate(fields):
# We simply skip completely empty rows
if not row:
continue
if self.width is None:
self.width = len(row)
elif self.width != len(row):
raise ValueError(f'Row {row_num} differs in length!')
for col_num, field in enumerate(row):
self.__tiles[Coordinate(col_num, row_num)] = get_type(field)
self.height = row_num + 1
def print(self, coords, radius):
"""Print a round part of the map, with `coords` in the midpoint, and the
horizontal radius (ie. width in characters) `radius`
This will result in a shape that resembles a circle, but, as text
characters have about 1:2 ratio, is actually an ellipse.
"""
if not isinstance(coords, Coordinate):
coords = Coordinate(*coords)
if radius > self.width // 2:
raise ValueError('Radius is too big')
if radius % 2 != 1:
raise ValueError('Radius must be odd')
width = (radius - 1) * 2 + 1
mid_x, mid_y = width // 2, radius // 2
for row in range(0, radius):
y_offset = row - mid_y
y = y_offset * 2
map_y = coords.y + y_offset
if map_y < 0:
map_y += self.height
elif map_y >= self.height:
map_y -= self.height
for column in range(0, width):
x_offset = column - mid_x
x = x_offset
map_x = coords.x + x_offset
if map_x < 0:
map_x += self.width
elif map_x >= self.width:
map_x -= self.width
if x < 0:
x -= 1
elif x > 0:
x += 1
distance = sqrt(y ** 2 + x ** 2)
if row == mid_y and column == mid_x:
print('@', end='')
elif distance > radius + 0.25:
print(' ', end='')
else:
tile = self[(map_x, map_y)]
print(tile, end='')
print('')
def __getitem__(self, coord):
if not isinstance(coord, Coordinate):
coord = Coordinate(*coord)
for key, tile in self.__tiles.items():
if key.x == coord.x and key.y == coord.y:
return tile
def __str__(self):
map_str = ''
prev_y = -1
for coord in sorted(self.__tiles.keys(), key=lambda coord: (coord.y, coord.x)):
if coord.y != prev_y:
prev_y = coord.y
map_str += '\n'
map_str += self.__tiles[coord].map_char
return map_str
def __repr__(self):
return '<Map>'
def get_type(type_char):
candidates = {identifier: data for identifier, data in TYPES.items() if data.map_char == type_char}
if not candidates:
raise KeyError(f'Map character "{type_char}" is unknown')
if len(candidates) > 1:
raise KeyError(f'Map character "{type_char}" has multiple definitions!')
return candidates.popitem()[1]
def load_terrain(filename):
with open(filename, 'r') as f:
terrain_data = json.load(f)
for identifier, data in terrain_data.items():
# TODO: Validate terrain data
tile_type = TileType(data)
TYPES[identifier] = tile_type