pyTanks.SwiftPlayer

一个 Swift pyTanks 玩家客户端。

什么是 pyTanks?

pyTanks 是一个供 Python AI 互相战斗的战场。

Swift 在哪里发挥作用?

现有的 pyTanks.Player 期望客户端使用 Python 编写,但是,所有通信都通过 JSON 和 WebSockets 进行。由于这些都是开放标准,理论上可以使用任何语言编写客户端。本项目提供了一个用于 pyTank 玩家的 Swift 模板。

要求

导出的产品

此软件包包含 3 个公开导出的产品

您无需 fork 此仓库,只需将此软件包添加为您自己的软件包的依赖项,即可启动并运行您自己的 AI。

用法

要编译玩家,请运行 Utils/build-executable <config>,其中 <config>debugrelease。这将在工作目录的顶层放置一个名为 start 的可执行程序。

要运行之前编译的可执行文件,请从顶层目录运行 ./start

主要的客户端配置选项在 ClientConfiguration 结构体中指定。您可以直接在您自己的 fork 中更改它们,但默认情况下,其中一些可以在命令行中自定义

默认玩家是 SimplePlayer,它只是在随机方向上移动并尝试向敌方坦克射击,而不考虑墙壁。

在 Xcode 中工作

要在 Xcode 中处理 fork,请在工作目录内的命令行中运行 swift package generate-xcodeproj。打开新生成的 pyTanks.SwiftPlayer.xcodeproj 文件后,请务必将项目目标更改为 macOS 10.12 而不是 10.10。这使其可以在 Xcode 中构建、运行和调试。

创建您自己的坦克 AI

要创建新的 AI

import CustomPlayer
import ClientControl

let myPlayer = CustomPlayer()
Game(player: myPlayer).run(arguments: CommandLine.arguments)

任何遵循 Player 协议的对象都充当坦克的“大脑”。您可以创建自己的对象来遵循此协议,也可以使现有对象遵循此协议。Player 协议具有以下要求

Player 上的调用顺序如下

  1. loggameConfig 在尝试连接到服务器之前设置。
  2. 建立服务器连接后,访问 playerDescription,并将新的信息字符串发送到服务器以用于 AI。
  3. 调用 connectedToServer()
  4. roundStarting(withGameState:)
  5. makeMove(withGameState:) 每帧调用
  6. tankKilled() 仅在坦克被击杀时调用
  7. roundOver() 无论谁获胜都会调用
  8. 重复步骤 4–7 直到终止

makeMove(withGameState:) 函数内部,您为坦克返回一个可选的命令。命令在 Command 枚举中定义。有效命令包括 gostopturnfire。请参阅 PlayerSupport/Commands.swift 中的文档。

一些需要记住的事情

GameState

在每个回合开始时和每一帧,您都会收到一个 GameState 对象,表示在某个时间点的棋盘状态。这使您可以访问有关您自己的坦克 (.myTank)、敌方坦克 (otherTanks)、当前飞行的炮弹 (shells) 和棋盘墙壁 (walls) 的信息。请注意,otherTanks 存储在 Dictionary 中,坦克的唯一 ID 作为其键。ID 不保证在运行之间持久存在。有关 GameState 的所有可用属性,请参阅 GameState.swift 中的文档。

自定义日志记录

在您的 AI 中,您可以随时使用在您的 Playerlog 属性上设置的 Log 对象进行日志记录。只需调用 print(_:for:) 即可打印消息,该消息取决于是否请求了特定的日志类型。您可以传递 .debug 作为日志类型,将其视为调试消息,该消息仅应在命令行上指定 --debug 时打印。

在您自己的 fork 中,您还可以轻松修改哪些日志级别与哪些日志类型关联。在 Log 类 (PlayerSupport/Log.swift) 中是 LogTypes 结构体。此结构体遵循 OptionSet,并且仅充当日志类型的位掩码。您可以通过修改以下行来更改哪些类型与哪些级别关联

/// Includes everything in level 1 plus `gameEvents` and `aiLogic`
public static let level2: LogTypes = [
    .level1,
    .gameEvents,
    .aiLogic
]