Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Solving LinkedIn Tango by Linear Optimization

Tango Banner

Following the same approach as when I solved the Queens game using LO, I also decided to apply what I learned in Operations Research to solve Tango, another LinkedIn minigame, as part of a strategy to increase user engagement.


How to Play Tango

Figure 1:Example of a Tango minigame board. Source: LinkedIn

Objective
Fill all the squares on the board with moons 🌙 and suns ☀️.
Rules
The number of moons and suns in each row and column must be the same
There cannot be more than 2 moons or 2 suns in a row, either in a row or column
squares separated by the = sign must contain the same symbol
squares separated by the × sign must contain opposite symbols

Problem Modeling

To formulate our LOP, it will again be necessary to define the following elements:

  • Ranges

  • Sets

  • Decision variables

  • Parameters

  • Objective function

  • Constraints

Ranges

I={1,,n}I = \{1, \cdots, n\}
The row range, where nn is the total number of rows in the grid
J={1,,m}J = \{1, \cdots, m\}
The column range, where nn is the total number of columns in the grid

Sets

In the case of the Tango game, in addition to the row and column ranges, it will be necessary to consider the sets of pairs of squares with = and × signs, in addition to the set of squares already filled with a sun or moon symbol. Therefore, there will be:

H=I×J={(i,j)iI,jJ}H = I \times J = \{(i, j) \mid \forall i \in I, \forall j \in J\}
Set of all board squares (i,j)(i, j), which is simply the Cartesian product of the ranges II and JJ.
L={(v,w)v,wH,vw}L = \{(v, w) \mid v, w \in H, v \ne w\}
Set of pairs of squares separated by =.
O={(v,w)v,wH,vw}O = \{(v, w) \mid v, w \in H, v \ne w\}
Set of pairs of squares separated by ×.
KHK \subset H
Set of squares with an already filled symbol.

Decision Variables

As it was the case with the Queens game, the decision variables here will be binary, since Tango only uses two symbols. Because of this, the LOP is a BLOP. Thus, it was agreed that:

xij{0,1},(i,j)Hx_{ij} \in \{0,1\}, \forall (i,j) \in H
xij=1x_{ij} = 1, if the square in row ii and column jj will be filled with a 🌙
xij=0x_{ij} = 0, if the same square will be filled with a ☀️

Parameters

Parameters, unlike the decision variables, are constant values that represent fixed or known values that don’t change while the optimization process is running. In case of the Tango, there may be some cells that already come with a predefined symbol: sun or moon. As the set of parameters in our model, there will be:

kij{0,1},(i,j)Kk_{ij} \in \{0,1\}, \forall (i,j) \in K
kij=1k_{ij} = 1, if the square in row ii and column jj is already filled with a 🌙
kij=0k_{ij} = 0, if the same square is already filled with a ☀️

Objective Function

Again, as in the case of Queens, our objective is not to optimize a function, but rather to find a solution that fulfills all the rules of the game. Therefore, the Tango PPLB is not an optimization problem, but a feasibility problem. Thus, the objective function will be to maximize (or minimize) an arbitrary constant CC.

Max C\text{Max} \ C

Constraints

With the previous elements well defined, we can translate the rules of the game to our BLOP as follows:

Binarity Constraints
First, we must define that all decision variables in our problem are binary variables, that is, they only accept 0 and 1 as the only possible values.
xij{0,1},(i,j)Hx_{ij} \in \{0,1\}, \forall (i,j) \in H
Equal-Moons-Suns-Per-Row Constraints
Since the number of suns and moons for each row must be equal, the sum of xijx_{ij} belonging to a row ii must equal the half of total columns, therefore 3. Since there are 6 rows, the model will have 6 of these constraints.
j=1mxij=m2,iI\sum_{j=1}^{m}{x_{ij}}=\frac{m}{2}, \forall i \in I
Equal-Moons-Suns-Per-Column Constraints
The same logic applies to the columns. Therefore, there are 6 more constraints.
i=1nxij=n2,jJ\sum_{i=1}^{n}{x_{ij}}=\frac{n}{2}, \forall j \in J
No-Three-Consecutive-Moons-Per-Row Constraints
Since the 3 moons in a row cannot be next to each other, it means that the sum of three consecutive xijx_{ij} in a row must be less than or equal to 2.
xij+xi,j+1+xi,j+22,iI,j{1,,m2}x_{ij} + x_{i,j+1} + x_{i,j+2} \le 2, \forall i \in I, \forall j \in \{1, \cdots, m-2\}
No-Three-Consecutive-Moons-Per-Column Constraints
And the same logic applies to the columns.
xij+xi+1,j+xi+2,j2,i{1,,n2},jJx_{ij} + x_{i+1,j} + x_{i+2,j} \le 2, \forall i \in \{1, \cdots, n-2\}, \forall j \in J
No-Three-Consecutive-Suns-Per-Row Constraints
Similarly, since there cannot be 3 consecutive suns in a row, the sum of 3 subsequent xijx_{ij} in a row i must be greater than or equal to 1.
xij+xi,j+1+xi,j+21,iI,j{1,,m2}x_{ij} + x_{i,j+1} + x_{i,j+2} \ge 1, \forall i \in I, \forall j \in \{1, \cdots,m-2\}
No-Three-Consecutive-Suns-Per-Column Constraints
And the same logic applies to the columns.
xij+xi+1,j+xi+2,j1,i{1,,n2},jJx_{ij} + x_{i+1,j} + x_{i+2,j} \ge 1, \forall i \in \{1, \cdots, n-2\}, \forall j \in J
Already-Filled-squares Constraints
For each square that already has a pre-established figure, it is necessary to impose that xijx_{ij} is equal to 1 or 0, depending on whether the figure is a moon or a sun, respectively.
xij=kij,kijKx_{ij} = k_{ij}, \forall k_{ij} \in K
Like-Pairs Constraints
For each pair of adjacent cells that contains the = sign between them, it is necessary to impose the constraint that the values xijx_{ij} of that pair are equal, which is the same as saying that the difference between the values xijx_{ij} of that pair must be equal to 0.
xvxw=0,{v,w}Nx_v - x_w = 0, \forall \{v,w\} \in N
Opposite-Pairs Constraints
Finally, for each pair of adjacent cells that contains the sign × between them, it is necessary to impose the constraint that the values xijx_{ij} of this pair are different, which is the same as saying that the sum of the values xijx_{ij} of this pair must be equal to 1.
xv+xw=1,{v,w}Mx_v + x_w = 1, \forall \{v,w\} \in M

Abstract Model

Up to this point, the formulas created have been based on the premise that every Tango minigame will have 6 rows and 6 columns, which is indeed the case. However, in order to create a more generalized abstract model, we can admit that this will not always be a certainty, and therefore there is a possibility that the number of rows and columns will vary from game to game. Due to the restriction that the number of moons and suns for each row and column must be equal, it must be assumed that the total number of rows and columns are even numbers, that is, nmod20n \mod 2 \equiv 0 and mmod20m \mod 2 \equiv 0.

Thus, having raised these points, the abstract model of the Tango minigame is formulated as follows:

Max CS.t.:jJxij=m/2,iIiIxij=n/2,jJxij+xij+1+xij+22,iI,jJ\{m1,m}xij+xi+1,j+xi+2,j2,iI\{n1,n},jJxij+xij+1+xij+21,iI,jJ\{m1,m}xij+xi+1,j+xi+2,j1,iI\{n1,n},jJxij=kij,kijKxijxrs=0,((i,j),(r,s))Nxij+xrs=1,((i,j),(r,s))Mxij{0,1},(i,j)H\begin{array}{lll} & \text{Max} \ C \\ \text{S.t.:} & \\ & \sum_{j \in J}{x_{ij}} = m/2, & \forall i \in I \\ & \sum_{i \in I}{x_{ij}} = n/2, & \forall j \in J \\ & x_{ij} + x_{ij+1} + x_{ij+2} \le 2, & \forall i \in I, \forall j \in J \backslash \{m-1,m\} \\ & x_{ij} + x_{i+1,j} + x_{i+2,j} \le 2, & \forall i \in I \backslash \{n-1,n\}, \forall j \in J \\ & x_{ij} + x_{ij+1} + x_{ij+2} \ge 1, & \forall i \in I, \forall j \in J \backslash \{m-1,m\} \\ & x_{ij} + x_{i+1,j} + x_{i+2,j} \ge 1, & \forall i \in I \backslash \{n-1,n\}, \forall j \in J \\ & x_{ij} = k_{ij}, & \forall k_{ij} \in K \\ & x_{ij} - x_{rs} = 0, & \forall ((i,j),(r,s)) \in N \\ & x_{ij} + x_{rs} = 1, & \forall ((i,j),(r,s)) \in M \\ & x_{ij} \in \{0,1\}, & \forall (i,j) \in H \end{array}

Concrete Model

The concrete model was built based on the Tango minigame No. 151

Tango No. 151

Figure 2:Tango No. 151, March 7th, 2025. Source: LinkedIn

Max 0\text{Max} \ 0

S.t.:

Equal-Moons-Suns-Per-Row Constraints
x11+x12+x13+x14+x15+x16=3x_{11} + x_{12} + x_{13} + x_{14} + x_{15} + x_{16} = 3 (Row 1)
x21+x22+x23+x24+x25+x26=3x_{21} + x_{22} + x_{23} + x_{24} + x_{25} + x_{26} = 3 (Row 2)
x31+x32+x33+x34+x35+x36=3x_{31} + x_{32} + x_{33} + x_{34} + x_{35} + x_{36} = 3 (Row 3)
x41+x42+x43+x44+x45+x46=3x_{41} + x_{42} + x_{43} + x_{44} + x_{45} + x_{46} = 3 (Row 4)
x51+x52+x53+x54+x55+x56=3x_{51} + x_{52} + x_{53} + x_{54} + x_{55} + x_{56} = 3 (Row 5)
x61+x62+x63+x64+x65+x66=3x_{61} + x_{62} + x_{63} + x_{64} + x_{65} + x_{66} = 3 (Row 6)
Equal-Moons-Suns-Per-Column Constraints
x11+x21+x31+x41+x51+x61=3x_{11} + x_{21} + x_{31} + x_{41} + x_{51} + x_{61} = 3 (Column 1)
x12+x22+x32+x42+x52+x62=3x_{12} + x_{22} + x_{32} + x_{42} + x_{52} + x_{62} = 3 (Column 2)
x13+x23+x33+x43+x53+x63=3x_{13} + x_{23} + x_{33} + x_{43} + x_{53} + x_{63} = 3 (Column 3)
x14+x24+x34+x44+x54+x64=3x_{14} + x_{24} + x_{34} + x_{44} + x_{54} + x_{64} = 3 (Column 4)
x15+x25+x35+x45+x55+x65=3x_{15} + x_{25} + x_{35} + x_{45} + x_{55} + x_{65} = 3 (Column 5)
x16+x26+x36+x46+x56+x66=3x_{16} + x_{26} + x_{36} + x_{46} + x_{56} + x_{66} = 3 (Column 6)
No-Three-Consecutive-Moons-Per-Row Constraints
x11+x21+x312x_{11} + x_{21} + x_{31} \le 2 (Row 1)
x12+x13+x142x_{12} + x_{13} + x_{14} \le 2 (Row 1)
x13+x14+x152x_{13} + x_{14} + x_{15} \le 2 (Row 1)
x14+x15+x162x_{14} + x_{15} + x_{16} \le 2 (Row 1)
x21+x22+x232x_{21} + x_{22} + x_{23} \le 2 (Row 2)
x22+x23+x242x_{22} + x_{23} + x_{24} \le 2 (Row 2)
x23+x24+x252x_{23} + x_{24} + x_{25} \le 2 (Row 2)
x24+x25+x262x_{24} + x_{25} + x_{26} \le 2 (Row 2)
x31+x32+x332x_{31} + x_{32} + x_{33} \le 2 (Row 3)
x32+x33+x342x_{32} + x_{33} + x_{34} \le 2 (Row 3)
x33+x34+x352x_{33} + x_{34} + x_{35} \le 2 (Row 3)
x34+x35+x362x_{34} + x_{35} + x_{36} \le 2 (Row 3)
x41+x42+x432x_{41} + x_{42} + x_{43} \le 2 (Row 4)
x42+x43+x442x_{42} + x_{43} + x_{44} \le 2 (Row 4)
x43+x44+x452x_{43} + x_{44} + x_{45} \le 2 (Row 4)
x44+x45+x462x_{44} + x_{45} + x_{46} \le 2 (Row 4)
x51+x52+x532x_{51} + x_{52} + x_{53} \le 2 (Row 5)
x52+x53+x542x_{52} + x_{53} + x_{54} \le 2 (Row 5)
x53+x54+x552x_{53} + x_{54} + x_{55} \le 2 (Row 5)
x54+x55+x562x_{54} + x_{55} + x_{56} \le 2 (Row 5)
x61+x62+x632x_{61} + x_{62} + x_{63} \le 2 (Row 6)
x62+x63+x642x_{62} + x_{63} + x_{64} \le 2 (Row 6)
x63+x64+x652x_{63} + x_{64} + x_{65} \le 2 (Row 6)
x64+x65+x662x_{64} + x_{65} + x_{66} \le 2 (Row 6)
No-Three-Consecutive-Moons-Per-Column Constraints
x11+x21+x312x_{11} + x_{21} + x_{31} \le 2 (Column 1)
x21+x31+x412x_{21} + x_{31} + x_{41} \le 2 (Column 1)
x31+x41+x512x_{31} + x_{41} + x_{51} \le 2 (Column 1)
x41+x51+x612x_{41} + x_{51} + x_{61} \le 2 (Column 1)
x12+x22+x322x_{12} + x_{22} + x_{32} \le 2 (Column 2)
x22+x32+x422x_{22} + x_{32} + x_{42} \le 2 (Column 2)
x32+x42+x522x_{32} + x_{42} + x_{52} \le 2 (Column 2)
x42+x52+x622x_{42} + x_{52} + x_{62} \le 2 (Column 2)
x13+x23+x332x_{13} + x_{23} + x_{33} \le 2 (Column 3)
x23+x33+x432x_{23} + x_{33} + x_{43} \le 2 (Column 3)
x33+x43+x532x_{33} + x_{43} + x_{53} \le 2 (Column 3)
x43+x53+x632x_{43} + x_{53} + x_{63} \le 2 (Column 3)
x14+x24+x342x_{14} + x_{24} + x_{34} \le 2 (Column 4)
x24+x34+x442x_{24} + x_{34} + x_{44} \le 2 (Column 4)
x34+x44+x542x_{34} + x_{44} + x_{54} \le 2 (Column 4)
x44+x54+x642x_{44} + x_{54} + x_{64} \le 2 (Column 4)
x15+x25+x352x_{15} + x_{25} + x_{35} \le 2 (Column 5)
x25+x35+x452x_{25} + x_{35} + x_{45} \le 2 (Column 5)
x35+x45+x552x_{35} + x_{45} + x_{55} \le 2 (Column 5)
x45+x55+x652x_{45} + x_{55} + x_{65} \le 2 (Column 5)
x16+x26+x362x_{16} + x_{26} + x_{36} \le 2 (Column 6)
x26+x36+x462x_{26} + x_{36} + x_{46} \le 2 (Column 6)
x36+x46+x562x_{36} + x_{46} + x_{56} \le 2 (Column 6)
x46+x56+x662x_{46} + x_{56} + x_{66} \le 2 (Column 6)
No-Three-Consecutive-Suns-Per-Row Constraints
x11+x21+x311x_{11} + x_{21} + x_{31} \ge 1 (Row 1)
x12+x13+x141x_{12} + x_{13} + x_{14} \ge 1 (Row 1)
x13+x14+x151x_{13} + x_{14} + x_{15} \ge 1 (Row 1)
x14+x15+x161x_{14} + x_{15} + x_{16} \ge 1 (Row 1)
x21+x22+x231x_{21} + x_{22} + x_{23} \ge 1 (Row 2)
x22+x23+x241x_{22} + x_{23} + x_{24} \ge 1 (Row 2)
x23+x24+x251x_{23} + x_{24} + x_{25} \ge 1 (Row 2)
x24+x25+x261x_{24} + x_{25} + x_{26} \ge 1 (Row 2)
x31+x32+x331x_{31} + x_{32} + x_{33} \ge 1 (Row 3)
x32+x33+x341x_{32} + x_{33} + x_{34} \ge 1 (Row 3)
x33+x34+x351x_{33} + x_{34} + x_{35} \ge 1 (Row 3)
x34+x35+x361x_{34} + x_{35} + x_{36} \ge 1 (Row 3)
x41+x42+x431x_{41} + x_{42} + x_{43} \ge 1 (Row 4)
x42+x43+x441x_{42} + x_{43} + x_{44} \ge 1 (Row 4)
x43+x44+x451x_{43} + x_{44} + x_{45} \ge 1 (Row 4)
x44+x45+x461x_{44} + x_{45} + x_{46} \ge 1 (Row 4)
x51+x52+x531x_{51} + x_{52} + x_{53} \ge 1 (Row 5)
x52+x53+x541x_{52} + x_{53} + x_{54} \ge 1 (Row 5)
x53+x54+x551x_{53} + x_{54} + x_{55} \ge 1 (Row 5)
x54+x55+x561x_{54} + x_{55} + x_{56} \ge 1 (Row 5)
x61+x62+x631x_{61} + x_{62} + x_{63} \ge 1 (Row 6)
x62+x63+x641x_{62} + x_{63} + x_{64} \ge 1 (Row 6)
x63+x64+x651x_{63} + x_{64} + x_{65} \ge 1 (Row 6)
x64+x65+x661x_{64} + x_{65} + x_{66} \ge 1 (Row 6)
No-Three-Consecutive-Suns-Per-Column Constraints
x11+x21+x311x_{11} + x_{21} + x_{31} \ge 1 (Column 1)
x21+x31+x411x_{21} + x_{31} + x_{41} \ge 1 (Column 1)
x31+x41+x511x_{31} + x_{41} + x_{51} \ge 1 (Column 1)
x41+x51+x611x_{41} + x_{51} + x_{61} \ge 1 (Column 1)
x12+x22+x321x_{12} + x_{22} + x_{32} \ge 1 (Column 2)
x22+x32+x421x_{22} + x_{32} + x_{42} \ge 1 (Column 2)
x32+x42+x521x_{32} + x_{42} + x_{52} \ge 1 (Column 2)
x42+x52+x621x_{42} + x_{52} + x_{62} \ge 1 (Column 2)
x13+x23+x331x_{13} + x_{23} + x_{33} \ge 1 (Column 3)
x23+x33+x431x_{23} + x_{33} + x_{43} \ge 1 (Column 3)
x33+x43+x531x_{33} + x_{43} + x_{53} \ge 1 (Column 3)
x43+x53+x631x_{43} + x_{53} + x_{63} \ge 1 (Column 3)
x14+x24+x341x_{14} + x_{24} + x_{34} \ge 1 (Column 4)
x24+x34+x441x_{24} + x_{34} + x_{44} \ge 1 (Column 4)
x34+x44+x541x_{34} + x_{44} + x_{54} \ge 1 (Column 4)
x44+x54+x641x_{44} + x_{54} + x_{64} \ge 1 (Column 4)
x15+x25+x351x_{15} + x_{25} + x_{35} \ge 1 (Column 5)
x25+x35+x451x_{25} + x_{35} + x_{45} \ge 1 (Column 5)
x35+x45+x551x_{35} + x_{45} + x_{55} \ge 1 (Column 5)
x45+x55+x651x_{45} + x_{55} + x_{65} \ge 1 (Column 5)
x16+x26+x361x_{16} + x_{26} + x_{36} \ge 1 (Column 6)
x26+x36+x461x_{26} + x_{36} + x_{46} \ge 1 (Column 6)
x36+x46+x561x_{36} + x_{46} + x_{56} \ge 1 (Column 6)
x46+x56+x661x_{46} + x_{56} + x_{66} \ge 1 (Column 6)
Like-Pairs Constraints
x23x24=0x_{23} - x_{24} = 0
x21x31=0x_{21} - x_{31} = 0
x23x33=0x_{23} - x_{33} = 0
x26x36=0x_{26} - x_{36} = 0
x41x42=0x_{41} - x_{42} = 0
x63x64=0x_{63} - x_{64} = 0
Opposite-Pairs Constraints
x24+x34=1x_{24} + x_{34} = 1
x33+x34=1x_{33} + x_{34} = 1
x36+x46=1x_{36} + x_{46} = 1
x45+x46=1x_{45} + x_{46} = 1
Already-Filled-squares Constraints
x12=1x_{12} = 1
x15=1x_{15} = 1
x51=0x_{51} = 0
x55=1x_{55} = 1
Binarity Constraints
x12{0,1}x_{12} \in \{0,1\}
x13{0,1}x_{13} \in \{0,1\}
x14{0,1}x_{14} \in \{0,1\}
x15{0,1}x_{15} \in \{0,1\}
x16{0,1}x_{16} \in \{0,1\}
x21{0,1}x_{21} \in \{0,1\}
x22{0,1}x_{22} \in \{0,1\}
x23{0,1}x_{23} \in \{0,1\}
x24{0,1}x_{24} \in \{0,1\}
x25{0,1}x_{25} \in \{0,1\}
x26{0,1}x_{26} \in \{0,1\}
x31{0,1}x_{31} \in \{0,1\}
x32{0,1}x_{32} \in \{0,1\}
x33{0,1}x_{33} \in \{0,1\}
x34{0,1}x_{34} \in \{0,1\}
x35{0,1}x_{35} \in \{0,1\}
x36{0,1}x_{36} \in \{0,1\}
x41{0,1}x_{41} \in \{0,1\}
x42{0,1}x_{42} \in \{0,1\}
x43{0,1}x_{43} \in \{0,1\}
x44{0,1}x_{44} \in \{0,1\}
x45{0,1}x_{45} \in \{0,1\}
x46{0,1}x_{46} \in \{0,1\}
x51{0,1}x_{51} \in \{0,1\}
x52{0,1}x_{52} \in \{0,1\}
x53{0,1}x_{53} \in \{0,1\}
x54{0,1}x_{54} \in \{0,1\}
x55{0,1}x_{55} \in \{0,1\}
x56{0,1}x_{56} \in \{0,1\}
x61{0,1}x_{61} \in \{0,1\}
x62{0,1}x_{62} \in \{0,1\}
x63{0,1}x_{63} \in \{0,1\}
x64{0,1}x_{64} \in \{0,1\}
x65{0,1}x_{65} \in \{0,1\}
x66{0,1}x_{66} \in \{0,1\}

Solving with Pyomo

First of all, let’s import all the required libraries

import matplotlib.pyplot as plt
import networkx as nx
import pyomo.environ as pyo

Solving Tango

In order to solve a Tango minigame, the solve_tango() function was created, as it follows:

def solve_tango(n:int, m:int, like_pairs:dict, opp_pairs:dict, filled_squares:dict):

    model = pyo.ConcreteModel()

    # Ranges
    I = model.I = pyo.RangeSet(n)
    J = model.J = pyo.RangeSet(m)

    # Sets
    H = model.squares = pyo.Set(initialize=lambda model: [(i, j) for i in I for j in J])
    L = model.LikePairs = pyo.Set(initialize=like_pairs)
    O = model.OppositePairs = pyo.Set(initialize=opp_pairs)
    K = model.Filledsquares = pyo.Set(initialize=filled_squares.keys(), dimen=2)

    # Decision variables
    x = model.x = pyo.Var(I, J, within=pyo.Binary)
    
    # Parameters
    k = model.FilledValues = pyo.Param(K, initialize=filled_squares, within=pyo.Binary)

    # Objective function
    model.obj = pyo.Objective(expr=0, sense=pyo.maximize)

    # Constraints
    model.equal_moons_suns_per_row_constraints = pyo.Constraint(
        I,
        rule=lambda model, i: sum(x[i,j] for j in J) == m/2
    )

    model.equal_moons_suns_per_column_constraints = pyo.Constraint(
        J,
        rule=lambda model, j: sum(x[i,j] for i in I) == n/2
    )

    model.no_three_consecutive_moons_per_row_constraints = pyo.Constraint(
        I, pyo.RangeSet(m-2),
        rule=lambda model, i, j: x[i,j] + x[i,j+1] + x[i,j+2] <= 2
    )
    
    model.no_three_consecutive_suns_per_row_constraints = pyo.Constraint(
        I, pyo.RangeSet(m-2),
        rule=lambda model, i, j: x[i,j] + x[i,j+1] + x[i,j+2] >= 1
    )

    model.no_three_consecutive_moons_per_column_constraints = pyo.Constraint(
        pyo.RangeSet(n-2), J,
        rule=lambda model, i, j: x[i,j] + x[i+1,j] + x[i+2,j] <= 2
    )
    
    model.no_three_consecutive_suns_per_column_constraints = pyo.Constraint(
        pyo.RangeSet(n-2), J,
        rule=lambda model, i, j: x[i,j] + x[i+1,j] + x[i+2,j] >= 1
    )

    model.like_pairs_constraints = pyo.Constraint(
        L,
        rule=lambda model, i, j, r, s: x[i,j] - x[r,s] == 0
    )

    model.opposite_pairs_constraints = pyo.Constraint(
        O,
        rule=lambda model, i, j, r, s: x[i,j] + x[r,s] == 1
    )

    model.already_filled_squares_constraints = pyo.Constraint(
        K,
        rule=lambda model, i, j: x[i,j] == k[i,j]
    )

    # Solving model
    solver = pyo.SolverFactory("gurobi")
    result = solver.solve(model, tee=False)

    # display solution
    if str(result.Solver.status) == "ok":
        
        G = nx.grid_2d_graph(n,m)
        pos = {(i,j): (j, -i) for i, j in G.nodes()}
        
        plt.figure(figsize=(3.4, 3.4))
        
        nx.draw(
            G,
            pos= pos,
            with_labels= True,
            labels= {(i,j): int(x[i+1,j+1].value) for i, j in G.nodes()},
            node_size= 1000,
            node_color= ["#EEEAE7" if (i+1,j+1) in K else "white" for (i,j) in G.nodes()],
            node_shape="s",
            edgecolors="#EEEAE7",
            linewidths= 1,
            width= 0,
            edgelist = [
                ((i-1, j-1), (r-1,s-1)) for i,j,r,s in O] + [
                ((i-1, j-1), (r-1,s-1)) for i,j,r,s in L
            ]
        )
        nx.draw_networkx_edge_labels(
            G,
            pos= pos,
            edge_labels= {
                ((i-1, j-1), (r-1,s-1)): "×" for i,j,r,s in O} | {
                ((i-1, j-1), (r-1,s-1)): "=" for i,j,r,s in L
            },
            font_color="#887658"
        )
        plt.show()
    else:
        print('No valid solution was found!')


# dimensions of the Tango board
n = m = 6

# like (=) pairs, each element is ((i,j),(r,s))
like_pairs = [
    ((2, 3), (2, 4)),
    ((2, 1), (3, 1)),
    ((2, 3), (3, 3)),
    ((2, 6), (3, 6)),
    ((4, 1), (4, 2)),
    ((6, 3), (6, 4)),
]

# opposite (X) pairs
opp_pairs = [
    ((2, 4), (3, 4)),
    ((3, 1), (4, 1)),
    ((3, 3), (3, 4)),
    ((3, 6), (4, 6)),
    ((4, 5), (4, 6)),
]

# helper lists for the concrete instance (Tango #151)
# already filled squares: (i,j) -> kij
filled_squares = {
    (1, 2): 1,
    (1, 5): 1,
    (5, 2): 0,
    (5, 5): 1,
}

solve_tango(n, m, like_pairs, opp_pairs, filled_squares)
<Figure size 340x340 with 1 Axes>

As expected, the image result matches the solution of Tango No. 151

Solution of Tango No. 151

Figure 3:Solution of Tango No. 151, March 7th, 2025. Source: LinkedIn


References

  • BELFIORE, Patrícia; FÁVERO, Luiz Paulo. Pesquisa Operacional: Para cursos de Administração, Contabilidade e Economia. Elsevier Editora Ltda., 2012.

  • Tango. LinkedIn. Available at https://www.linkedin.com/games/tango/. Accessed March 7, 2025.