三维井字游戏

等级:初级

目的和先决条件

该模型解决了在三维井字游戏板上排列 $X$ 和 $O$ 的问题,从而最大程度地减少了完成的线或对角线的数量。它演示了如何使用混合整数编程来捕获简单的逻辑约束。

这是第五版《数学建模》( H. Paul Williams 著)第272和327-328页的示例17。

该建模示例处于初级阶段,我们假设你了解Python,并且具有一些有关构建数学优化模型的知识。希望你可以从示例中了解所有遗漏的概念。

注意: 你可以通过单击 此处 下载包含此示例和其他示例的代码。为了正确运行此 Jupyter Notebook,你必须具有 Gurobi 许可证。如果你没有,则可以商业用户身份申请 试用许可证,或以学术用户身份下载 免费许可证

问题描述

给定一个井字棋盘,玩家轮流放置$X$和 $O$,游戏通常在一个玩家完成一条线或一条对角线时结束;也就是说,当他们设法将自己的棋子放置在网格中形成线或对角线的三个单元格中时。游戏将持续到每个单元格都下满棋子位置。这里要达成的目标是排列棋子以最大程度地减少已完成的线或对角线的数量。

模型制定

决策变量

$\text{isX}_{ijk} \in [0,1]$: 单元格 $(i,j,k)$ 是否包含 $X$ ($isX=1$) 或 $O$ ($isX=0$)?

$\text{isLine}_{l} \in [0,1]$: 直线/对角线 $l$ 包含 3 个相同的棋子吗?

目标函数

\begin{equation} \text{Minimize} \quad Z = \sum_{l \in \text{Lines}}\text{isLine}_l \end{equation}

约束

\begin{equation} \sum_{ijk} \text{isX}_{ijk} = 14 \end{equation}

注意:$l_0$ 是 $l$ 行的第一个单元格,$l_1$ 是第二个,$l_2$ 是第三个单元格。

\begin{equation} \text{isLine}_l == 0 \implies isX[l_0] + isX[l_1] + isX[l_2] >= 1 \quad \forall l \in \text{Lines} \end{equation}\begin{equation} \text{isLine}_l == 0 \implies isX[l_0] + isX[l_1] + isX[l_2] <= 2 \quad \forall l \in \text{Lines} \end{equation}

Python 实现

首先导入模型

模型开发

我们首先在三维井字棋盘上创建一个所有可能的线和对角线的列表。每个条目都表示为一个包含3个条目的 Python 元组,其中每个条目给出相应单元格的(i,j,k)位置。总共有49个。

接下来,我们创建模型和决策变量。

现在我们创建约束。第一个状态是棋盘将包含14个 $X$(和13个 $O$):

其余的约束建立了 $isLine[]$ 和 $isX[]$ 变量之间的关系。如果所有三个单元格都包含相同的棋子,则该行是完整的。在我们的模型中,这将对应于三个相关的 $isX[]$ 变量,其总和为3(所有 $X$ )或0(所有 $O$ )。就我们的目的而言,足以执行以下条件:如果 $isLine = 0 $,则总和必须严格在这两个值之间。

最后,我们设定了优化目标,这是尽量减少线的数量。

现在我们执行优化。


结果

最佳解决方案仅完成4条线或对角线。我们可以使用 matplotlib 可视化结果(已除去 3D 井字棋的三维尺寸)。


参考资料

H. Paul Williams, Model Building in Mathematical Programming, fifth edition.

Copyright © 2020 Gurobi Optimization, LLC

翻译 By Arvin Xu