Skip to main content

Standard Board mechanism for Dojo tasks

Project description

Introduction

Often, when running a Python Dojo, we’ve ended up with a challenge based around some kind of board or tile-based landscape. In these situations it’s not uncommon to spend a lot of the time building up your basic board functionality in order to support the more interesting gameplay algorithm.

This module implements a general-purpose board structure which has the functionality needed for a range of purposes, and lends itself to being subclassed for those particular needs.

Dependencies

None - stdlib only

Tests

Fairly decent coverage (not actually checked with coverage.py): test.py

Getting Started

Install with pip:

pip install board

Absolutely basic usage:

import board
#
# Produce a 3x3 board
#
b = board.Board((3, 3))

b[0, 0] = "X"
b[1, 0] = "O"

Usage

Board is an n-dimensional board, any of which dimensions can be of infinite size. (So if you have, say, 3 infinite dimensions, you have the basis for a Minecraft layout). Dimensions are zero-based.

Cells on the board are accessed by item access, eg board[1, 2] or landscape[1, 1, 10].

A board can be copied, optionally along with its data by means of the .copy method. Or a section of a board can be linked to the original board by slicing the original board:

b1 = board.Board((9, 9))
b1[1, 1] = 1
b2 = b1.copy()
b3 = b1[:3, :3]

Note that the slice must include all the dimensions of the original board, but any of those subdimensions can be of length 1:

b1 = board.Board((9, 9, 9))
b2 = b1[:3, :3, :1]

A sentinel value of Empty indicates a position which is not populated because it has never had a value, or because its value has been deleted:

b1 = board.Board((3, 3))
assert b1[1, 1] is board.Empty
b1.populate("abcdefghi")
assert b1[1, 1] == "e"
del b1[1, 1]
assert b1[1, 1] is board.Empty

Iterating over the board yields its coordinates:

b1 = board.Board((2, 2))
for coord in b1:
    print(coord)
#
# => (0, 0), (0, 1) etc.
#

Iteration over a board with one or more infinite dimensions will work by iterating in chunks:

b1 = board.Board((3, 3, board.Infinity))
for coord in b1:
    print(b1)

To see coordinates with their data items, use iterdata:

b1 = board.Board((2, 2))
b1.populate("abcd")
for coord, data in b1.iterdata():
    print(coord, "=>", data)

To read, write and empty the data at a board position, use indexing:

b1 = board.Board((3, 3))
b1.populate("abcdef")
print(b1[0, 0]) # "a"

b1[0, 0] = "*"
print(b1[0, 0]) # "*"

del b1[0, 0]
print(b1[0, 0]) # <Empty>

To test whether a coordinate is contained with the local coordinate space, use in:

b1 = board.Board((3, 3))
(1, 1) in b1 # True
(4, 4) in b1 # False
(1, 1, 1) in b1 # InvalidDimensionsError

One board is equal to another if it has the same dimensionality and each data item is equal:

b1 = board.Board((3, 3))
b1.populate("abcdef")
b2 = b1.copy()
b1 == b2 # True
b2[0, 0] = "*"
b1 == b2 # False

b2 = board.Board((2, 2))
b2.populate("abcdef")
b1 == b2 # False

To get a crude view of the contents of the board, use .dump:

b1 = board.Board((3, 3))
b1.populate("abcdef")
b1.dump()

To get a grid view of a 2-dimensional board, use .draw:

b1 = board.Board((3, 3))
b1.populate("OX  XXOO ")
b1.draw()

To populate the board from an arbitrary iterator, use .populate:

def random_letters():
    import random, string
    while True:
        yield random.choice(string.ascii_uppercase)

b1 = board.Board((4, 4))
b1.populate(random_letters())

To clear the board, use .clear:

b1 = board.Board((3, 3))
b1.populate(range(10))
b1.clear()
list(b1.iterdata()) # []

A board is True if it has any data, False if it has none:

b1 = board.Board((2, 2))
b1.populate("abcd")
bool(b1) # True
b1.clear()
bool(b1) # False

The length of the board is the product of its dimension lengths. If any dimension is infinite, the board length is infinte. NB to find the amount of data on the board, use lendata:

b1 = board.Board((4, 4))
len(b1) # 16
b1.populate("abcd")
len(b1) # 16
b1.lendata() # 4
b2 = board.Board((2, board.Infinity))
len(b2) # Infinity

To determine the bounding box of the board which contains data, use .occupied:

b1 = board.Board((3, 3))
b1.populate("abcd")
list(c for (c, d) in b1.iterdata()) # [(0, 0), (0, 1), (0, 2), (1, 0)]
b1.occupied() # ((0, 0), (1, 2))

To test whether a position is on any edge of the board, use .is_edge:

b1 = board.Board((3, 3))
b1.is_edge((0, 0)) # True
b1.is_edge((1, 1)) # False
b1.is_edge((2, 0)) # True

To find the immediate on-board neighbours to a position along all dimensions:

b1 = board.Board((3, 3, 3))
list(b1.neighbours((0, 0, 0)))
# [(0, 1, 1), (1, 1, 0), ..., (1, 0, 1), (0, 1, 0)]

EXPERIMENTAL: To iterate over all the coords in the rectangular space between two corners, use .itercoords:

b1 = board.Board((3, 3))
list(b1.itercoords((0, 0), (1, 1))) # [(0, 0), (0, 1), (1, 0), (1, 1)]

EXPERIMENTAL: To iterate over all the on-board positions from one point in a particular direction, use .iterline:

b1 = board.Board((4, 4))
start_from = 1, 1
direction = 1, 1
list(b1.iterline(start_from, direction)) # [(1, 1), (2, 2), (3, 3)]
direction = 0, 2
list(b1.iterline(start_from, direction)) # [(1, 1), (1, 3)]

Properties

To determine whether a board is offset from another (ie the result of a slice):

b1 = board.Board((3, 3))
b1.is_offset # False
b2 = b1[:1, :1]
b2.is_offset # True

To determine whether a board has any infinite or finite dimensions:

b1 = board.Board((3, board.Infinity))
b1.has_finite_dimensions # True
b1.has_infinite_dimensions # True
b2 = board.Board((3, 3))
b1.has_infinite_dimensions # False
b3 = board.Board((board.Infinity, board.Infinity))
b3.has_finite_dimensions # False

Local and Global coordinates

Since one board can represent a slice of another, there are two levels of coordinates: local and global. Coordinates passed to or returned from any of the public API methods are always local for that board. They represent the natural coordinate space for the board. Internally, the module will use global coordinates, translating as necessary.

Say you’re managing a viewport of a tile-based dungeon game where the master dungeon board is 100 x 100 but the visible board is 10 x 10. Your viewport board is currently representing the slice of the master board from (5, 5) to (14, 14). Changing the item at position (2, 2) on the viewport board will change the item at position (7, 7) on the master board (and vice versa).

As a user of the API you don’t need to know this, except to understand that a board slice is essentially a view on its parent. If you wish to subclass or otherwise extend the board, you’ll need to note where coordinate translations are necessary.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

board-0.0.0.post0.tar.gz (9.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

board-0.0.0.post0-py2.py3-none-any.whl (12.5 kB view details)

Uploaded Python 2Python 3

File details

Details for the file board-0.0.0.post0.tar.gz.

File metadata

  • Download URL: board-0.0.0.post0.tar.gz
  • Upload date:
  • Size: 9.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for board-0.0.0.post0.tar.gz
Algorithm Hash digest
SHA256 149e5dd87be1835ecfea76fc25bba29dc5ee9ed5088338e61557124601b9eaf4
MD5 251b4a129d016913d1c949e3c90e5180
BLAKE2b-256 44aade9c002e7726425ea628f8b576a33d172ba792f7e2dd07e1130ad651974f

See more details on using hashes here.

File details

Details for the file board-0.0.0.post0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for board-0.0.0.post0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 831de92f159ae43d4b4458155a7156947fd48da7886d65598f0882453abe5b6d
MD5 cd37903ddef850cf69e5850ae5533e4c
BLAKE2b-256 a9845a574f9f1af2ec3fa47856c9cc76cc5d7607d6fe26d8d032722b14734816

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page