跳转到主要内容

Dojo任务的标准板机制

项目描述

简介

通常,当我们运行Python Dojo时,我们往往会遇到一些基于某种类型的板或基于瓦片的景观的挑战。在这些情况下,花费大量时间构建基本板功能以支持更有趣的游戏算法是很常见的事情。

此模块实现了一个通用的板结构,它具有满足多种目的所需的功能,并且适合为特定需求进行子类化。

依赖项

无 - 只需stdlib

测试

相当不错的覆盖率(未使用coverage.py实际检查):test.py

入门

使用pip安装

pip install board

绝对基本用法

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

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

用法

板是一个n维板,其中任何一个维度都可以是无限大小。(所以如果你有3个无限维度,你就有Minecraft布局的基础)。维度是从0开始的,并且Python中的负索引操作通常:从维度的末尾开始工作。

板上的单元格可以通过项访问来访问,例如board[1, 2]或landscape[1, 1, 10]。

板可以通过.copy方法进行复制,可以选择性地与其数据一起复制。或者,可以通过切片原始板将板的某个部分链接到原始板

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

请注意,切片必须包含原始板的全部维度,但任何这些子维度都可以是长度为1

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

空值表示一个位置尚未填充,因为它从未有过值,或者它的值已被删除

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

遍历棋盘可以得到它的坐标

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

遍历一个具有一个或多个无限维度的棋盘将通过分块迭代来完成

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

要查看具有数据项的坐标,请使用iterdata

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

要读取、写入和清空棋盘位置的数据,请使用索引

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

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

b1[-1, -1] = "*"
print(b1[2, 2]) # "*"

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

要测试一个坐标是否包含在本地坐标空间中,请使用in

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

如果一个棋盘具有相同的维度并且每个数据项都相等,则两个棋盘相等

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

要从任意迭代器填充棋盘,请使用populate

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

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

要清空棋盘,请使用.clear

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

如果一个棋盘有任何数据,则为True;如果没有数据,则为False

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

棋盘的长度是其维度长度的乘积。如果有任何维度是无限的,则棋盘长度是无限的。注意:要找到棋盘上的数据量,请使用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

要确定包含数据的棋盘的边界框,请使用.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))

对于围绕占用空间切片棋盘的常见情况,请使用.occupied_board

b1 = board.Board((3, 3))
b1.populate("abcd")
b1.draw()
b2 = b1.occupied_board()
b2.draw()

要测试一个位置是否位于棋盘的任何边缘,请使用.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

要找到所有维度上位置的直接棋盘邻居

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

要遍历两个角落之间的矩形空间中的所有坐标,请使用.itercoords

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

要遍历从特定方向上一点到棋盘上的所有位置,请使用.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)]

或.iterlinedata以生成每个点的数据

b1 = board.Board((3, 3))
b1.populate("ABCDEFGHJ")
start_from = 1, 1
direction = 1, 0
list(b1.iterlinedata(start_from, direction)) # ['A', 'D', 'G']

iterline和iterdata都可以接受最大步数,例如用于像Connect 4或Battleships这样的游戏

b1 = board.Board((8, 8))
#
# Draw a Battleship
#
b1.populate("BBBB", b1.iterline((2, 2), (1, 0)))

为了方便需要查找如此多物品的运行的游戏,.run_of_n方法结合iterline和数据,以生成棋盘上所有可能的长度的线条及其数据

b1 = board.Board((3, 3))
b1[0, 0] = 'X'
b1[1, 1] = 'O'
b1[0, 1] = 'X'
for line, data in b1.runs_of_n(3):
    if all(d == "O" for d in data):
        print("O wins")
        break
    elif all(d == "X" for d in data):
        print("X wins")
        break

要遍历棋盘的角落,请使用.corners

b1 = board.Board((3, 3))
corners() # [(0, 0), (0, 2), (2, 0), (2, 2)]

属性

要确定一个棋盘是否相对于另一个棋盘偏移(即切片的结果)

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

要确定一个棋盘是否有无限或有限维度

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

显示棋盘

要获取棋盘内容的粗略视图,请使用.dump

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

要获取二维棋盘的网格视图,请使用.draw

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

如果您不想绘制边框,例如因为您正在使用棋盘来渲染ASCII艺术,请传递use_borders=False

b1 = board.Board((8, 8))
for coord in b1.iterline((0, 0), (1, 1)):
    b1[coord] = "*"
for coord in b1.iterline((7, 0), (-1, 1)):
    b1[coord] = "*"
b1.draw(use_borders=False)

要使用Pillow(这不是强制依赖项)渲染到图像,请使用paint。默认渲染器将数据项视为文本,并将它们缩放到适合每个单元格。这对于像Noughts & Crosses这样的东西是有效的,假设您存储类似于“O”和“X”的内容。但它也适用于单词搜索,甚至简单的Battleships,其中数据项是对象,其__str__返回空白(对于未发现的),“+”表示单次命中,以及“*”表示被摧毁的船只

b1 = board.Board((3, 3))
b1[0, 0] = "X"
b1[1, 1] = "O"
b1[0, 2] = "X"
b1.paint("board.png")
# ... and now look at board.png

文本绘制是通过内部名为text_sprite的回调实现的。paint()的另一个现成的回调是imagefile_sprite。它会在当前目录(或另一个目录;您可以指定)中查找.png文件

本地和全局坐标

由于一个棋盘可以表示另一个棋盘的切片,因此存在两个坐标级别:本地和全局。传递给或从任何公共API方法返回的坐标始终是该棋板的本地坐标。它们代表棋板的自然坐标空间。内部,该模块将使用全局坐标,并根据需要转换。

假设你正在管理一个基于瓷砖的地牢游戏的视口,主地牢板大小为100 x 100,但可见板大小为10 x 10。你的视口板目前表示主板的(5, 5)到(14, 14)部分。更改视口板上(2, 2)位置的项目将更改主板上(7, 7)位置的项目(反之亦然)。

作为API用户,你不需要知道这些,除非你理解一个板块切片本质上是对其父板的视图。如果你希望子类化或以其他方式扩展板块,你需要注意坐标转换的必要位置。

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源代码分发

board-1.0.tar.gz (16.7 kB 查看哈希值)

上传时间 源代码

构建分发

board-1.0-py2.py3-none-any.whl (12.9 kB 查看哈希值)

上传时间 Python 2 Python 3

支持者