3D Tic-Tac-Toe
阿新 • • 發佈:2021-01-30
技術標籤:課外學習
3D Tic-Tac-Toe
一、問題描述
有一個三維空間中3X3X3的遊戲板,玩家可以輪流在這每個單元格中畫上“X”或者“O”,在經典的玩法中,如果有一個玩家填滿了一行或者一個對角線,那麼遊戲結束。但是現在遊戲將一直進行直到每個格子都填上。現在請你設計一種玩法使遊戲結束時,同一種元素填滿的行數或者對角線數最少。
二、建立模型
(一)關鍵變數
-
i
s
X
i
j
k
isX_{ijk}
isXijk∈[0,1]:
(
i
,
j
,
k
)
(i,j,k)
(i,j,k
- i s L i n e l isLine_l isLinel∈[0,1]:如果 l l l這一行或者對角線填滿同一種元素( i s L i n e l isLine_l isLinel=1)否則( i s L i n e l isLine_l isLinel=0)。
(二)目標函式
M
i
n
i
m
i
z
e
Minimize
Minimize
Z
=
∑
l
∈
L
i
n
e
s
i
s
L
i
n
e
l
Z=\sum_{l\in Lines}isLine_l
Z=∑l∈LinesisLinel
(三) 約束變數
- ∑ i j k i s X i j k = 14 ∑_{ijk}isX_{ijk}=14 ∑ijkisXijk=14
一共二十七個位置,假設X先走,那麼X有十四個,O有13個。
-
i
s
L
i
n
e
l
=
0
⟹
i
s
X
[
l
0
]
+
i
s
X
[
l
1
]
+
i
s
X
[
l
2
]
>
=
1
isLine_l=0⟹isX[l0]+isX[l1]+isX[l2]>=1
isLinel=0⟹isX[l0]+isX[l1]+isX[l2]>=1
∀
l
∈
L
i
n
e
s
∀l∈Lines
i s L i n e l = = 0 ⟹ i s X [ l 0 ] + i s X [ l 1 ] + i s X [ l 2 ] < = 2 isLinel==0⟹isX[l0]+isX[l1]+isX[l2]<=2 isLinel==0⟹isX[l0]+isX[l1]+isX[l2]<=2 ∀ l ∈ L i n e s ∀l∈Lines ∀l∈Lines
由於如果不是同一種元素,那麼三個值加起來就不會是0或者3。
三、程式碼
import gurobipy as gp
from gurobipy import GRB
lines = []
size = 3
for i in range(size):
for j in range(size):
for k in range(size):
if i == 0:
lines.append(((0,j,k), (1,j,k), (2,j,k)))
if j == 0:
lines.append(((i,0,k), (i,1,k), (i,2,k)))
if k == 0:
lines.append(((i,j,0), (i,j,1), (i,j,2)))
if i == 0 and j == 0:
lines.append(((0,0,k), (1,1,k), (2,2,k)))
if i == 0 and j == 2:
lines.append(((0,2,k), (1,1,k), (2,0,k)))
if i == 0 and k == 0:
lines.append(((0,j,0), (1,j,1), (2,j,2)))
if i == 0 and k == 2:
lines.append(((0,j,2), (1,j,1), (2,j,0)))
if j == 0 and k == 0:
lines.append(((i,0,0), (i,1,1), (i,2,2)))
if j == 0 and k == 2:
lines.append(((i,0,2), (i,1,1), (i,2,0)))
lines.append(((0,0,0), (1,1,1), (2,2,2)))
lines.append(((2,0,0), (1,1,1), (0,2,2)))
lines.append(((0,2,0), (1,1,1), (2,0,2)))
lines.append(((0,0,2), (1,1,1), (2,2,0)))
model = gp.Model('Tic_Tac_Toe')
isX = model.addVars(size, size, size, vtype=GRB.BINARY, name="isX")
isLine = model.addVars(lines, vtype=GRB.BINARY, name="isLine")
x14 = model.addConstr(isX.sum() == 14)
for line in lines:
model.addGenConstrIndicator(isLine[line], False, isX[line[0]] + isX[line[1]] + isX[line[2]] >= 1)
model.addGenConstrIndicator(isLine[line], False, isX[line[0]] + isX[line[1]] + isX[line[2]] <= 2)
model.setObjective(isLine.sum())
model.optimize()
'''
ARGUMENTS:
GRB.GENCONSTR_INDICATOR (option 1):
binvar (Var): Antecedent variable of indicator constraint
binval (Boolean): Value of antecedent variable that activates the linear constraint
lhs (float, Var, or LinExpr): Linear expression of constraint triggered by the indicator
sense (char): Sense of constraint triggered by the indicator (e.g., GRB.LESS_EQUAL)
rhs (float): Right-hand side of linear constraint triggered by the indicator
name (string): Constraint name (default is no name)
GRB.GENCONSTR_INDICATOR (option 2):
binvar (Var): Antecedent variable of indicator constraint
binval (Boolean): Value of antecedent variable that activates the linear constraint
lhs (TempConstr): Linear constraint triggered by indicator
name (string): Constraint name (default is no name)
RETURN VALUE:
The created general constraint object.
EXAMPLE:
genconstr = model.addGenConstrIndicator(z, 0, 2*x1 - 1.5*x2 + 3.0*x3 == 4.5, name="myIndicatorConstr")
'''
參考:gurobi中國.