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的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | cd718c3322a126d86455e24ae0cebb59a567cbdbaf03696391dccf88c8f456d6 |
|
MD5 | 9896667b8549bb3e1cc13a7e68fd0d28 |
|
BLAKE2b-256 | de7d4de4e7b0eb780854e2c1258225a831ef29c447f0e934347ce58128939b69 |
board-1.0-py2.py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | b97c986d0190a2a5181a7fe28959cd8515520b87f672796e21e1b0d32cc63e2f |
|
MD5 | 47665ada00bffa59abda58a9e4f3d643 |
|
BLAKE2b-256 | bdb8461dae0fae64be12d818efab745d520bcf4a96195ccbd5028d58d042e68b |