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 Zip by Linear Optimization

Zip Banner

Continuing with the challenge of solving LinkedIn games by using LO, just like I did with Queens and Tango, the next one I’ve chosen is Zip, which turned out to be the most challenging so far.

How to Play Zip

Figure 1:Example of a Zip game board (Source: LinkedIn)

The Zip game board consists of a grid with some numbered squares. Both the grid’s dimensions and the total of numbered squares can vary from game to game. The objective is to trace a path that runs through all the squares on the board, moving through numbered squares in ascending order, starting from square number 1 to the one with the highest number.


Problem Modeling

The best way I thought of to solve the game is to consider the squares as nodes in a directed graph (digraph), where each node has a set of pairs of edges that arrive at and depart from the nodes, as shown in the following figure.

Zip game modeled on a directed graph. Source: created by the author himself

Figure 2:Zip game modeled on a directed graph. Source: created by the author himself

Considering this model, enacted the Abstract LO Model by defining its following components:

  • Ranges

  • Sets

  • Decision Variables

  • Parameter

  • Objective Function

  • Constraints

Ranges

To properly formulate the LO model, we will start from the premise that the squares on the board will be the Cartesian product of the ranges II of rows and JJ of columns present on the board. In addition, it is necessary to have defined an interval KK for the set of numbered squares.

I={1,,n}I = \{1, \cdots, n\}
The row range, where nn is the total number of rows (in this case, n=6n = 6)
J={1,,m}J = \{1, \cdots, m\}
The column range, where mm is the total number of columns (in this case, m=6m = 6 as well).

Sets

This time, the definition of sets will be more than fundamental to reducing the complexity of the model, as we will avoid having to deal with numerous exceptions. From the ranges determined previously, we can define the set of vertices (VV) and edges (EE) existing in the network logic. In addition to these, it is also necessary to consider the subsets of numbered vertices (NN) and blocked edges (WW), since, in some instances of Zip game, there may be walls between two squares that prevent the path from being traced between them.

V={(i,j)iI,jJ}V = \{(i,j) \mid \forall i \in I, \forall j \in J \}
Set of all squares (vertices). There must be at least 2 vertices in the grid, as it is only possible to trace a path with an initial and a final square. Therefore, V2|V| \ge 2
E={((i,j),(i+1,j))(i,j)V,i+1I}{((i,j),(i1,j))(i,j)V,i1I}{((i,j),(i,j+1))(i,j)V,j+1J}{((i,j),(i,j1))(i,j)V,j1J}E = \begin{array}{lr} \{((i,j), (i+1,j)) \mid (i,j) \in V, i + 1 \in I \} & \cup \\ \{((i,j), (i-1,j)) \mid (i,j) \in V, i - 1 \in I \} & \cup \\ \{((i,j), (i,j+1)) \mid (i,j) \in V, j + 1 \in J \} & \cup \\ \{((i,j), (i,j-1)) \mid (i,j) \in V, j - 1 \in J \} & \end{array}
Set of all edges present in the graph. Its definition is a bit more complex as it is necessary to clarify that, for each vertex, there will only be edges between neighbors immediately to the left, immediately to the right, immediately above, and immediately below it, if they exist.
KVK \subseteq V
Set of numbered squares, which will consist of a set of all vertices indexed by a number on board game.
WEW \subset E
Set of blocked edges (walls) that may appear on the grid.

Decision Variables

By using the network logic already presented, it is possible to define the edges as binary decision variables xijrsx_{ijrs}, which again makes our LOP a BLOP. In addition to xijrsx_{ijrs}, variables uiju_{ij} will also be considered, representing the absolute ordinal position of the square (i,j)(i,j) within the path (these variables will be better explained later).

xijrs{0,1}x_{ijrs} \in \{0,1\}
xijrs=1x_{ijrs}=1, if the edge that starts from square (i,j)(i,j) and arrives at square (r,s)(r,s) is part of the path
xijrs=0x_{ijrs}=0, otherwise
uijNu_{ij} \in \mathbb{N}
Absolute ordinal positions of the squares (i,j)(i,j) within the path.

Parameters

kij{1,,K},(i,j)Kk_{ij} \in \{1, \cdots, |K|\}, \forall (i,j) \in K
For each numbered board square in KK set, it’ll be defined a integer kijk_{ij} that matches its number displayed on game board.

Objective Function

Once again, just as in the Queens and Tango games, our problem does not have a function to be optimized, since we only want to find a solution that fulfills all the rules of the game. Therefore, Zip’s BLOP is a feasibility problem, and the objective function of the model consists of maximizing (or minimizing) an arbitrary constant.

Max C\text{Max} \ C

Constraints

Decision variables domain constraints

First, let’s not forget to define our variables xijrsx_{ijrs} as binary and the variables uiju_{ij} as non-negative real numbers. To simplify, whenever possible, we can replace the notation xijrsx_{ijrs} with xvwx_{vw} and uiju_{ij} with just uvu_v, since the sequence (i,j)=v(i,j) = v always refers to some vertex belonging to VV set.

xv,w{0,1},(v,w)Euv0,vV\begin{array}{} x_{v,w} \in \{0,1\}, \forall (v,w) \in E \\ u_v \ge 0, \forall v \in V \end{array}
Blocked edges constraints

If there is a wall between a pair of squares, then the sum of the edges connecting those ones must be equal to 0.

xv,w+xw,v=0,(v,w)Wx_{v,w} + x_{w,v} = 0, \forall (v,w) \in W
Continuity constraints

Since it is only possible to enter and exit a node once (except for the initial and destination nodes), then we will have the following:

Outgoing-Edges Constraints
The sum of the edges emanating from a node must equal 1 (except for the destination square).
wVxvw=1,vV\{v:kv=K}:(v,w)E\sum_{w \in V}{x_{vw}} = 1, \forall v \in V \backslash \{v:k_v=|K|\}: (v,w) \in E
Incoming-Edges Constraints
The sum of the edges arriving at a node must equal 1 (except for the initial square).
vVxvw=1,wV\{w:kw=1}:(v,w)E\sum_{v \in V}{x_{vw}} = 1, \forall w \in V \backslash \{w:k_w=1\}: (v,w) \in E
Arrival Square Constraint
The sum of the edges emanating from the destination node must be 0.
wVxvw=0,(v,w)E,kv=K\sum_{w \in V}{x_{vw}} = 0, (v,w) \in E, k_v = |K|
Starting Square Constraint
The sum of the edges arriving at the initial node must be 0.
vVxvw=0,(v,w)E,kw=1\sum_{v \in V}{x_{vw}} = 0, (v,w) \in E, k_w = 1
Subroute Elimination Constraints

The advantage of the MTZ formulation is that the number of constraints to be included to guarantee subroute elimination is equal to E=4nm2n2m|E| = 4nm - 2n - 2m, that is, the number of edges in the graph. Thus, the number of constraints grows linearly as a function of the number of edges, instead of exponentially as a function of the number of vertices. For it to work, it requires the addition of more decision variables (the previously mentioned uiju_{ij}), which represent the absolute ordinal position of square (i,j)(i,j) within the path.

Position of Starting Square Constraint
First, the position of the starting square must be equal to 1, since it will always be the first position on the path.
uv=1:kv=1u_v = 1: k_v = 1
MTZ Constraints
Then, the positions of the remaining squares on the board should be given as follows.
uwuv+1M(1xvw),(v,w)E:wV\{w:kw=1}u_w \ge u_v + 1 - M(1 - x_{vw}), \forall (v,w) \in E: w \in V \backslash \{w:k_w=1\}
Positon of Arrival Square Constraint
Although not necessary, one can restrict the position of the arrival square to be equal to the number of squares on the board, just to make the uvu_v range from 1 to 36.
uv=V:kv=Ku_v = |V|: k_v = |K|
Order of Precedence Constraints
In order for the path to traverse the numbered squares in ascending numerical order, it is necessary to impose the constraint that the position of a numbered square ii must be at least equal to the position subsequent to the last numbered square.
uvuw+1,v,wK:kv=kw+1u_v \ge u_w + 1, \forall v, w \in K : k_v = k_w + 1

Abstract Model

With all the formulas elaborated, we have the complete abstract model for the Zip minigame.

Max CS.t.:wVxvw=1,vV\{v:kv=K}:(v,w)EvVxvw=0,kv=K:(v,w)EvVxvw=1,wV\{w:kw=1}:(v,w)EvVxvw=0,kw=1:(v,w)Exvw+xwv=0,(v,w)Wuv=1,kv=1uv=V,kv=Kuwuv+1V(1xvw),(v,w)E:wV\{w:kw=1}uvuw+1,v,wK:kv=kw+1xvw{0,1},(v,w)Euv0,vV\begin{array}{lll} & \text{Max} \ C & \\ \text{S.t.:} & & \\ & \sum_{w \in V}{x_{vw}}=1, & \forall v \in V \backslash \{v:k_v=|K|\}: (v,w) \in E \\ & \sum_{v \in V}{x_{vw}}=0, & k_v = |K| : (v,w) \in E \\ & \sum_{v \in V}{x_{vw}}=1, & \forall w \in V \backslash \{w:k_w=1\}: (v,w) \in E \\ & \sum_{v \in V}{x_{vw}}=0, & k_w = 1: (v,w) \in E \\ & x_{vw} + x_{wv} = 0, & \forall (v,w) \in W \\ & u_v = 1, & k_v = 1 \\ & u_v = |V|, & k_v = |K| \\ & u_w \ge u_v + 1 - |V|(1-x_{vw}), & \forall (v,w) \in E: w \in V \backslash \{w:k_w=1\} \\ & u_v \ge u_w + 1, & \forall v,w \in K : k_v = k_w + 1 \\ & x_{vw} \in \{0,1\}, & \forall (v,w) \in E \\ & u_v \ge 0, & \forall v \in V \end{array}

Concrete Model

The game selected to be solved is the Zip No. 166, published on LinkedIn on August 29th, 2025

Zip Problem

Figure 3:Zip No. 166, August 29th, 2025 (Source: LinkedIn)

Based on this specific case, we have the following concrete model:

Max 0\text{Max} \ 0

S.t.:

Outgoing edges constraints
x1112+x1121=1x_{1112} + x_{1121} = 1 (Square (1,1))
x1211+x1222+x1213=1x_{1211} + x_{1222} + x_{1213} = 1 (Square (1,2))
x1312+x1323+x1314=1x_{1312} + x_{1323} + x_{1314} = 1 (Square (1,3))
x1413+x1424+x1415=1x_{1413} + x_{1424} + x_{1415} = 1 (Square (1,4))
x1514+x1525+x1516=1x_{1514} + x_{1525} + x_{1516} = 1 (Square (1,5))
x1615+x1626=1x_{1615} + x_{1626} = 1 (Square (1,6))
x2111+x2122+x2131=1x_{2111} + x_{2122} + x_{2131} = 1 (Square (2,1))
x2212+x2221+x2223+x2232=1x_{2212} + x_{2221} + x_{2223} + x_{2232} = 1 (Square (2,2))
x2313+x2322+x2324+x2333=1x_{2313} + x_{2322} + x_{2324} + x_{2333} = 1 (Square (2,3))
x2414+x2423+x2425+x2434=1x_{2414} + x_{2423} + x_{2425} + x_{2434} = 1 (Square (2,4))
x2515+x2524+x2526+x2535=1x_{2515} + x_{2524} + x_{2526} + x_{2535} = 1 (Square (2,5))
x2616+x2625+x2636=1x_{2616} + x_{2625} + x_{2636} = 1 (Square (2,6))
x3121+x3132+x3141=1x_{3121} + x_{3132} + x_{3141} = 1 (Square (3,1))
x3222+x3231+x3233+x3242=1x_{3222} + x_{3231} + x_{3233} + x_{3242} = 1 (Square (3,2))
x3323+x3332+x3334+x3343=1x_{3323} + x_{3332} + x_{3334} + x_{3343} = 1 (Square (3,3))
x3424+x3433+x3435+x3444=1x_{3424} + x_{3433} + x_{3435} + x_{3444} = 1 (Square (3,4))
x3525+x3534+x3536+x3545=1x_{3525} + x_{3534} + x_{3536} + x_{3545} = 1 (Square (3,5))
x3626+x3635+x3646=1x_{3626} + x_{3635} + x_{3646} = 1 (Square (3,6))
x4131+x4142+x4151=1x_{4131} + x_{4142} + x_{4151} = 1 (Square (4,1))
x4232+x4241+x4243+x4252=1x_{4232} + x_{4241} + x_{4243} + x_{4252} = 1 (Square (4,2))
x4333+x4342+x4344+x4353=1x_{4333} + x_{4342} + x_{4344} + x_{4353} = 1 (Square (4,3))
x4434+x4443+x4445+x4454=1x_{4434} + x_{4443} + x_{4445} + x_{4454} = 1 (Square (4,4))
x4535+x4544+x4546+x4555=1x_{4535} + x_{4544} + x_{4546} + x_{4555} = 1 (Square (4,5))
x4636+x4645+x4656=0x_{4636} + x_{4645} + x_{4656} = 0 (Square (4,6))
x5141+x5152+x5161=1x_{5141} + x_{5152} + x_{5161} = 1 (Square (5,1))
x5242+x5251+x5253+x5262=1x_{5242} + x_{5251} + x_{5253} + x_{5262} = 1 (Square (5,2))
x5343+x5352+x5354+x5363=1x_{5343} + x_{5352} + x_{5354} + x_{5363} = 1 (Square (5,3))
x5444+x5453+x5455+x5464=1x_{5444} + x_{5453} + x_{5455} + x_{5464} = 1 (Square (5,4))
x5545+x5554+x5556+x5565=1x_{5545} + x_{5554} + x_{5556} + x_{5565} = 1 (Square (5,5))
x5646+x5655+x5666=1x_{5646} + x_{5655} + x_{5666} = 1 (Square (5,6))
x6151+x6162=1x_{6151} + x_{6162} = 1 (Square (6,1))
x6252+x6261+x6263=1x_{6252} + x_{6261} + x_{6263} = 1 (Square (6,2))
x6353+x6362+x6364=1x_{6353} + x_{6362} + x_{6364} = 1 (Square (6,3))
x6454+x6463+x6465=1x_{6454} + x_{6463} + x_{6465} = 1 (Square (6,4))
x6555+x6564+x6566=1x_{6555} + x_{6564} + x_{6566} = 1 (Square (6,5))
x6656+x6665=1x_{6656} + x_{6665} = 1 (Square (6,6))
Incoming edges cosntraints
x1211+x2111=1x_{1211} + x_{2111} = 1 (Square (1,1))
x1112+x2212+x1312=1x_{1112} + x_{2212} + x_{1312} = 1 (Square (1,2))
x1213+x2313+x1413=1x_{1213} + x_{2313} + x_{1413} = 1 (Square (1,3))
x1314+x2414+x1514=1x_{1314} + x_{2414} + x_{1514} = 1 (Square (1,4))
x1415+x2515+x1615=1x_{1415} + x_{2515} + x_{1615} = 1 (Square (1,5))
x1516+x2616=1x_{1516} + x_{2616} = 1 (Square (1,6))
x1121+x2221+x3121=1x_{1121} + x_{2221} + x_{3121} = 1 (Square (2,1))
x1222+x2122+x2322+x3222=1x_{1222} + x_{2122} + x_{2322} + x_{3222} = 1 (Square (2,2))
x1323+x2223+x2423+x3323=1x_{1323} + x_{2223} + x_{2423} + x_{3323} = 1 (Square (2,3))
x1424+x2324+x2524+x3424=1x_{1424} + x_{2324} + x_{2524} + x_{3424} = 1 (Square (2,4))
x1525+x2425+x2625+x3525=1x_{1525} + x_{2425} + x_{2625} + x_{3525} = 1 (Square (2,5))
x1626+x2526+x3626=1x_{1626} + x_{2526} + x_{3626} = 1 (Square (2,6))
x2131+x3231+x4131=1x_{2131} + x_{3231} + x_{4131} = 1 (Square (3,1))
x2232+x3132+x3332+x4232=1x_{2232} + x_{3132} + x_{3332} + x_{4232} = 1 (Square (3,2))
x2333+x3233+x3433+x4333=1x_{2333} + x_{3233} + x_{3433} + x_{4333} = 1 (Square (3,3))
x2434+x3334+x3534+x4434=1x_{2434} + x_{3334} + x_{3534} + x_{4434} = 1 (Square (3,4))
x2535+x3435+x3635+x4535=1x_{2535} + x_{3435} + x_{3635} + x_{4535} = 1 (Square (3,5))
x2636+x3536+x4636=1x_{2636} + x_{3536} + x_{4636} = 1 (Square (3,6))
x3141+x4241+x5141=1x_{3141} + x_{4241} + x_{5141} = 1 (Square (4,1))
x3242+x4142+x4342+x5242=1x_{3242} + x_{4142} + x_{4342} + x_{5242} = 1 (Square (4,2))
x3343+x4243+x4443+x5343=1x_{3343} + x_{4243} + x_{4443} + x_{5343} = 1 (Square (4,3))
x3444+x4344+x4544+x5444=1x_{3444} + x_{4344} + x_{4544} + x_{5444} = 1 (Square (4,4))
x3545+x4445+x4645+x5545=1x_{3545} + x_{4445} + x_{4645} + x_{5545} = 1 (Square (4,5))
x3646+x4546+x5646=1x_{3646} + x_{4546} + x_{5646} = 1 (Square (4,6))
x4151+x5251+x6151=1x_{4151} + x_{5251} + x_{6151} = 1 (Square (5,1))
x4252+x5152+x5352+x6252=1x_{4252} + x_{5152} + x_{5352} + x_{6252} = 1 (Square (5,2))
x4353+x5253+x5453+x6353=1x_{4353} + x_{5253} + x_{5453} + x_{6353} = 1 (Square (5,3))
x4454+x5354+x5554+x6454=1x_{4454} + x_{5354} + x_{5554} + x_{6454} = 1 (Square (5,4))
x4555+x5455+x5655+x6555=1x_{4555} + x_{5455} + x_{5655} + x_{6555} = 1 (Square (5,5))
x4656+x5556+x6656=1x_{4656} + x_{5556} + x_{6656} = 1 (Square (5,6))
x5161+x6261=1x_{5161} + x_{6261} = 1 (Square (6,1))
x5262+x6162+x6362=1x_{5262} + x_{6162} + x_{6362} = 1 (Square (6,2))
x5363+x6263+x6463=1x_{5363} + x_{6263} + x_{6463} = 1 (Square (6,3))
x5464+x6364+x6564=1x_{5464} + x_{6364} + x_{6564} = 1 (Square (6,4))
x5565+x6465+x6665=0x_{5565} + x_{6465} + x_{6665} = 0 (Square (6,5))
x5666+x6566=1x_{5666} + x_{6566} = 1 (Square (6,6))
Ordinal position constraints
u65=1u_{65} = 1 (Square 1)
u66u65+1u_{66} \ge u_{65} + 1 (Square 2)
u56u66+1u_{56} \ge u_{66} + 1 (Square 3)
u64u56+1u_{64} \ge u_{56} + 1 (Square 4)
u53u64+1u_{53} \ge u_{64} + 1 (Square 5)
u42u53+1u_{42} \ge u_{53} + 1 (Square 6)
u31u42+1u_{31} \ge u_{42} + 1 (Square 7)
u21u31+1u_{21} \ge u_{31} + 1 (Square 8)
u11u21+1u_{11} \ge u_{21} + 1 (Square 9)
u12u11+1u_{12} \ge u_{11} + 1 (Square 10)
u13u12+1u_{13} \ge u_{12} + 1 (Square 11)
u35u13+1u_{35} \ge u_{13} + 1 (Square 12)
u24u35+1u_{24} \ge u_{35} + 1 (Square 13)
u34u24+1u_{34} \ge u_{24} + 1 (Square 14)
u43u34+1u_{43} \ge u_{34} + 1 (Square 15)
u46u43+1u_{46} \ge u_{43} + 1 (Square 16)
u46=36u_{46} = 36 (Square 16)
Subroute elimination - MZT - constraints
u11u12+136(1x1211)u_{11} \ge u_{12} + 1 - 36(1 - x_{1211})
u11u21+136(1x2111)u_{11} \ge u_{21} + 1 - 36(1 - x_{2111})
u12u11+136(1x1112)u_{12} \ge u_{11} + 1 - 36(1 - x_{1112})
u12u22+136(1x2212)u_{12} \ge u_{22} + 1 - 36(1 - x_{2212})
u12u13+136(1x1312)u_{12} \ge u_{13} + 1 - 36(1 - x_{1312})
u13u12+136(1x1213)u_{13} \ge u_{12} + 1 - 36(1 - x_{1213})
u13u23+136(1x2313)u_{13} \ge u_{23} + 1 - 36(1 - x_{2313})
u13u14+136(1x1413)u_{13} \ge u_{14} + 1 - 36(1 - x_{1413})
u14u13+136(1x1314)u_{14} \ge u_{13} + 1 - 36(1 - x_{1314})
u14u24+136(1x2414)u_{14} \ge u_{24} + 1 - 36(1 - x_{2414})
u14u15+136(1x1514)u_{14} \ge u_{15} + 1 - 36(1 - x_{1514})
u15u14+136(1x1415)u_{15} \ge u_{14} + 1 - 36(1 - x_{1415})
u15u25+136(1x2515)u_{15} \ge u_{25} + 1 - 36(1 - x_{2515})
u15u16+136(1x1615)u_{15} \ge u_{16} + 1 - 36(1 - x_{1615})
u16u15+136(1x1516)u_{16} \ge u_{15} + 1 - 36(1 - x_{1516})
u16u26+136(1x2616)u_{16} \ge u_{26} + 1 - 36(1 - x_{2616})
u21u11+136(1x1121)u_{21} \ge u_{11} + 1 - 36(1 - x_{1121})
u21u22+136(1x2221)u_{21} \ge u_{22} + 1 - 36(1 - x_{2221})
u21u31+136(1x3121)u_{21} \ge u_{31} + 1 - 36(1 - x_{3121})
u22u12+136(1x1222)u_{22} \ge u_{12} + 1 - 36(1 - x_{1222})
u22u21+136(1x2122)u_{22} \ge u_{21} + 1 - 36(1 - x_{2122})
u22u23+136(1x2322)u_{22} \ge u_{23} + 1 - 36(1 - x_{2322})
u22u32+136(1x3222)u_{22} \ge u_{32} + 1 - 36(1 - x_{3222})
u23u13+136(1x1323)u_{23} \ge u_{13} + 1 - 36(1 - x_{1323})
u23u22+136(1x2223)u_{23} \ge u_{22} + 1 - 36(1 - x_{2223})
u23u24+136(1x2423)u_{23} \ge u_{24} + 1 - 36(1 - x_{2423})
u23u33+136(1x3323)u_{23} \ge u_{33} + 1 - 36(1 - x_{3323})
u24u14+136(1x1424)u_{24} \ge u_{14} + 1 - 36(1 - x_{1424})
u24u23+136(1x2324)u_{24} \ge u_{23} + 1 - 36(1 - x_{2324})
u24u25+136(1x2524)u_{24} \ge u_{25} + 1 - 36(1 - x_{2524})
u24u34+136(1x3424)u_{24} \ge u_{34} + 1 - 36(1 - x_{3424})
u25u15+136(1x1525)u_{25} \ge u_{15} + 1 - 36(1 - x_{1525})
u25u24+136(1x2425)u_{25} \ge u_{24} + 1 - 36(1 - x_{2425})
u25u26+136(1x2625)u_{25} \ge u_{26} + 1 - 36(1 - x_{2625})
u25u35+136(1x3525)u_{25} \ge u_{35} + 1 - 36(1 - x_{3525})
u26u16+136(1x1626)u_{26} \ge u_{16} + 1 - 36(1 - x_{1626})
u26u25+136(1x2526)u_{26} \ge u_{25} + 1 - 36(1 - x_{2526})
u26u36+136(1x3626)u_{26} \ge u_{36} + 1 - 36(1 - x_{3626})
u31u21+136(1x2131)u_{31} \ge u_{21} + 1 - 36(1 - x_{2131})
u31u32+136(1x3231)u_{31} \ge u_{32} + 1 - 36(1 - x_{3231})
u31u41+136(1x4131)u_{31} \ge u_{41} + 1 - 36(1 - x_{4131})
u32u22+136(1x2232)u_{32} \ge u_{22} + 1 - 36(1 - x_{2232})
u32u31+136(1x3132)u_{32} \ge u_{31} + 1 - 36(1 - x_{3132})
u32u33+136(1x3332)u_{32} \ge u_{33} + 1 - 36(1 - x_{3332})
u32u42+136(1x4232)u_{32} \ge u_{42} + 1 - 36(1 - x_{4232})
u33u23+136(1x2333)u_{33} \ge u_{23} + 1 - 36(1 - x_{2333})
u33u32+136(1x3233)u_{33} \ge u_{32} + 1 - 36(1 - x_{3233})
u33u34+136(1x3433)u_{33} \ge u_{34} + 1 - 36(1 - x_{3433})
u33u43+136(1x4333)u_{33} \ge u_{43} + 1 - 36(1 - x_{4333})
u34u24+136(1x2434)u_{34} \ge u_{24} + 1 - 36(1 - x_{2434})
u34u33+136(1x3334)u_{34} \ge u_{33} + 1 - 36(1 - x_{3334})
u34u35+136(1x3534)u_{34} \ge u_{35} + 1 - 36(1 - x_{3534})
u34u44+136(1x4434)u_{34} \ge u_{44} + 1 - 36(1 - x_{4434})
u35u25+136(1x2535)u_{35} \ge u_{25} + 1 - 36(1 - x_{2535})
u35u34+136(1x3435)u_{35} \ge u_{34} + 1 - 36(1 - x_{3435})
u35u36+136(1x3635)u_{35} \ge u_{36} + 1 - 36(1 - x_{3635})
u35u45+136(1x4535)u_{35} \ge u_{45} + 1 - 36(1 - x_{4535})
u36u26+136(1x2636)u_{36} \ge u_{26} + 1 - 36(1 - x_{2636})
u36u35+136(1x3536)u_{36} \ge u_{35} + 1 - 36(1 - x_{3536})
u36u46+136(1x4636)u_{36} \ge u_{46} + 1 - 36(1 - x_{4636})
u41u31+136(1x3141)u_{41} \ge u_{31} + 1 - 36(1 - x_{3141})
u41u42+136(1x4241)u_{41} \ge u_{42} + 1 - 36(1 - x_{4241})
u41u51+136(1x5141)u_{41} \ge u_{51} + 1 - 36(1 - x_{5141})
u42u32+136(1x3242)u_{42} \ge u_{32} + 1 - 36(1 - x_{3242})
u42u41+136(1x4142)u_{42} \ge u_{41} + 1 - 36(1 - x_{4142})
u42u43+136(1x4342)u_{42} \ge u_{43} + 1 - 36(1 - x_{4342})
u42u52+136(1x5242)u_{42} \ge u_{52} + 1 - 36(1 - x_{5242})
u43u33+136(1x3343)u_{43} \ge u_{33} + 1 - 36(1 - x_{3343})
u43u42+136(1x4243)u_{43} \ge u_{42} + 1 - 36(1 - x_{4243})
u43u44+136(1x4443)u_{43} \ge u_{44} + 1 - 36(1 - x_{4443})
u43u53+136(1x5343)u_{43} \ge u_{53} + 1 - 36(1 - x_{5343})
u44u34+136(1x3444)u_{44} \ge u_{34} + 1 - 36(1 - x_{3444})
u44u43+136(1x4344)u_{44} \ge u_{43} + 1 - 36(1 - x_{4344})
u44u45+136(1x4544)u_{44} \ge u_{45} + 1 - 36(1 - x_{4544})
u44u54+136(1x5444)u_{44} \ge u_{54} + 1 - 36(1 - x_{5444})
u45u35+136(1x3545)u_{45} \ge u_{35} + 1 - 36(1 - x_{3545})
u45u44+136(1x4445)u_{45} \ge u_{44} + 1 - 36(1 - x_{4445})
u45u46+136(1x4645)u_{45} \ge u_{46} + 1 - 36(1 - x_{4645})
u45u55+136(1x5545)u_{45} \ge u_{55} + 1 - 36(1 - x_{5545})
u46u36+136(1x3646)u_{46} \ge u_{36} + 1 - 36(1 - x_{3646})
u46u45+136(1x4546)u_{46} \ge u_{45} + 1 - 36(1 - x_{4546})
u46u56+136(1x5646)u_{46} \ge u_{56} + 1 - 36(1 - x_{5646})
u51u41+136(1x4151)u_{51} \ge u_{41} + 1 - 36(1 - x_{4151})
u51u52+136(1x5251)u_{51} \ge u_{52} + 1 - 36(1 - x_{5251})
u51u61+136(1x6151)u_{51} \ge u_{61} + 1 - 36(1 - x_{6151})
u52u42+136(1x4252)u_{52} \ge u_{42} + 1 - 36(1 - x_{4252})
u52u51+136(1x5152)u_{52} \ge u_{51} + 1 - 36(1 - x_{5152})
u52u53+136(1x5352)u_{52} \ge u_{53} + 1 - 36(1 - x_{5352})
u52u62+136(1x6252)u_{52} \ge u_{62} + 1 - 36(1 - x_{6252})
u53u43+136(1x4353)u_{53} \ge u_{43} + 1 - 36(1 - x_{4353})
u53u52+136(1x5253)u_{53} \ge u_{52} + 1 - 36(1 - x_{5253})
u53u54+136(1x5453)u_{53} \ge u_{54} + 1 - 36(1 - x_{5453})
u53u63+136(1x6353)u_{53} \ge u_{63} + 1 - 36(1 - x_{6353})
u54u44+136(1x4454)u_{54} \ge u_{44} + 1 - 36(1 - x_{4454})
u54u53+136(1x5354)u_{54} \ge u_{53} + 1 - 36(1 - x_{5354})
u54u55+136(1x5554)u_{54} \ge u_{55} + 1 - 36(1 - x_{5554})
u54u64+136(1x6454)u_{54} \ge u_{64} + 1 - 36(1 - x_{6454})
u55u45+136(1x4555)u_{55} \ge u_{45} + 1 - 36(1 - x_{4555})
u55u54+136(1x5455)u_{55} \ge u_{54} + 1 - 36(1 - x_{5455})
u55u56+136(1x5655)u_{55} \ge u_{56} + 1 - 36(1 - x_{5655})
u55u65+136(1x6555)u_{55} \ge u_{65} + 1 - 36(1 - x_{6555})
u56u46+136(1x4656)u_{56} \ge u_{46} + 1 - 36(1 - x_{4656})
u56u55+136(1x5556)u_{56} \ge u_{55} + 1 - 36(1 - x_{5556})
u56u66+136(1x6656)u_{56} \ge u_{66} + 1 - 36(1 - x_{6656})
u61u51+136(1x5161)u_{61} \ge u_{51} + 1 - 36(1 - x_{5161})
u61u62+136(1x6261)u_{61} \ge u_{62} + 1 - 36(1 - x_{6261})
u62u52+136(1x5262)u_{62} \ge u_{52} + 1 - 36(1 - x_{5262})
u62u61+136(1x6162)u_{62} \ge u_{61} + 1 - 36(1 - x_{6162})
u62u63+136(1x6362)u_{62} \ge u_{63} + 1 - 36(1 - x_{6362})
u63u53+136(1x5363)u_{63} \ge u_{53} + 1 - 36(1 - x_{5363})
u63u62+136(1x6263)u_{63} \ge u_{62} + 1 - 36(1 - x_{6263})
u63u64+136(1x6463)u_{63} \ge u_{64} + 1 - 36(1 - x_{6463})
u64u54+136(1x5464)u_{64} \ge u_{54} + 1 - 36(1 - x_{5464})
u64u63+136(1x6364)u_{64} \ge u_{63} + 1 - 36(1 - x_{6364})
u64u65+136(1x6564)u_{64} \ge u_{65} + 1 - 36(1 - x_{6564})
u65u55+136(1x5565)u_{65} \ge u_{55} + 1 - 36(1 - x_{5565})
u65u64+136(1x6465)u_{65} \ge u_{64} + 1 - 36(1 - x_{6465})
u65u66+136(1x6665)u_{65} \ge u_{66} + 1 - 36(1 - x_{6665})
u66u56+136(1x5666)u_{66} \ge u_{56} + 1 - 36(1 - x_{5666})
u66u65+136(1x6566)u_{66} \ge u_{65} + 1 - 36(1 - x_{6566})
Binarity constraints for edge variables
x1112{0,1}x_{1112} \in \{0,1\}
x1121{0,1}x_{1121} \in \{0,1\}
x1211{0,1}x_{1211} \in \{0,1\}
x1222{0,1}x_{1222} \in \{0,1\}
x1213{0,1}x_{1213} \in \{0,1\}
x1312{0,1}x_{1312} \in \{0,1\}
x1323{0,1}x_{1323} \in \{0,1\}
x1314{0,1}x_{1314} \in \{0,1\}
x1413{0,1}x_{1413} \in \{0,1\}
x1424{0,1}x_{1424} \in \{0,1\}
x1415{0,1}x_{1415} \in \{0,1\}
x1514{0,1}x_{1514} \in \{0,1\}
x1525{0,1}x_{1525} \in \{0,1\}
x1516{0,1}x_{1516} \in \{0,1\}
x1615{0,1}x_{1615} \in \{0,1\}
x1626{0,1}x_{1626} \in \{0,1\}
x2111{0,1}x_{2111} \in \{0,1\}
x2122{0,1}x_{2122} \in \{0,1\}
x2131{0,1}x_{2131} \in \{0,1\}
x2212{0,1}x_{2212} \in \{0,1\}
x2221{0,1}x_{2221} \in \{0,1\}
x2223{0,1}x_{2223} \in \{0,1\}
x2232{0,1}x_{2232} \in \{0,1\}
x2313{0,1}x_{2313} \in \{0,1\}
x2322{0,1}x_{2322} \in \{0,1\}
x2324{0,1}x_{2324} \in \{0,1\}
x2333{0,1}x_{2333} \in \{0,1\}
x2414{0,1}x_{2414} \in \{0,1\}
x2423{0,1}x_{2423} \in \{0,1\}
x2425{0,1}x_{2425} \in \{0,1\}
x2434{0,1}x_{2434} \in \{0,1\}
x2515{0,1}x_{2515} \in \{0,1\}
x2524{0,1}x_{2524} \in \{0,1\}
x2526{0,1}x_{2526} \in \{0,1\}
x2535{0,1}x_{2535} \in \{0,1\}
x2616{0,1}x_{2616} \in \{0,1\}
x2625{0,1}x_{2625} \in \{0,1\}
x2636{0,1}x_{2636} \in \{0,1\}
x3121{0,1}x_{3121} \in \{0,1\}
x3132{0,1}x_{3132} \in \{0,1\}
x3141{0,1}x_{3141} \in \{0,1\}
x3222{0,1}x_{3222} \in \{0,1\}
x3231{0,1}x_{3231} \in \{0,1\}
x3233{0,1}x_{3233} \in \{0,1\}
x3242{0,1}x_{3242} \in \{0,1\}
x3323{0,1}x_{3323} \in \{0,1\}
x3332{0,1}x_{3332} \in \{0,1\}
x3334{0,1}x_{3334} \in \{0,1\}
x3343{0,1}x_{3343} \in \{0,1\}
x3424{0,1}x_{3424} \in \{0,1\}
x3433{0,1}x_{3433} \in \{0,1\}
x3435{0,1}x_{3435} \in \{0,1\}
x3444{0,1}x_{3444} \in \{0,1\}
x3525{0,1}x_{3525} \in \{0,1\}
x3534{0,1}x_{3534} \in \{0,1\}
x3536{0,1}x_{3536} \in \{0,1\}
x3545{0,1}x_{3545} \in \{0,1\}
x3626{0,1}x_{3626} \in \{0,1\}
x3635{0,1}x_{3635} \in \{0,1\}
x3646{0,1}x_{3646} \in \{0,1\}
x4131{0,1}x_{4131} \in \{0,1\}
x4142{0,1}x_{4142} \in \{0,1\}
x4151{0,1}x_{4151} \in \{0,1\}
x4232{0,1}x_{4232} \in \{0,1\}
x4241{0,1}x_{4241} \in \{0,1\}
x4243{0,1}x_{4243} \in \{0,1\}
x4252{0,1}x_{4252} \in \{0,1\}
x4333{0,1}x_{4333} \in \{0,1\}
x4342{0,1}x_{4342} \in \{0,1\}
x4344{0,1}x_{4344} \in \{0,1\}
x4353{0,1}x_{4353} \in \{0,1\}
x4434{0,1}x_{4434} \in \{0,1\}
x4443{0,1}x_{4443} \in \{0,1\}
x4445{0,1}x_{4445} \in \{0,1\}
x4454{0,1}x_{4454} \in \{0,1\}
x4535{0,1}x_{4535} \in \{0,1\}
x4544{0,1}x_{4544} \in \{0,1\}
x4546{0,1}x_{4546} \in \{0,1\}
x4555{0,1}x_{4555} \in \{0,1\}
x4636{0,1}x_{4636} \in \{0,1\}
x4645{0,1}x_{4645} \in \{0,1\}
x4656{0,1}x_{4656} \in \{0,1\}
x5141{0,1}x_{5141} \in \{0,1\}
x5152{0,1}x_{5152} \in \{0,1\}
x5161{0,1}x_{5161} \in \{0,1\}
x5242{0,1}x_{5242} \in \{0,1\}
x5251{0,1}x_{5251} \in \{0,1\}
x5253{0,1}x_{5253} \in \{0,1\}
x5262{0,1}x_{5262} \in \{0,1\}
x5343{0,1}x_{5343} \in \{0,1\}
x5352{0,1}x_{5352} \in \{0,1\}
x5354{0,1}x_{5354} \in \{0,1\}
x5363{0,1}x_{5363} \in \{0,1\}
x5444{0,1}x_{5444} \in \{0,1\}
x5453{0,1}x_{5453} \in \{0,1\}
x5455{0,1}x_{5455} \in \{0,1\}
x5464{0,1}x_{5464} \in \{0,1\}
x5545{0,1}x_{5545} \in \{0,1\}
x5554{0,1}x_{5554} \in \{0,1\}
x5556{0,1}x_{5556} \in \{0,1\}
x5565{0,1}x_{5565} \in \{0,1\}
x5646{0,1}x_{5646} \in \{0,1\}
x5655{0,1}x_{5655} \in \{0,1\}
x5666{0,1}x_{5666} \in \{0,1\}
x6151{0,1}x_{6151} \in \{0,1\}
x6162{0,1}x_{6162} \in \{0,1\}
x6252{0,1}x_{6252} \in \{0,1\}
x6261{0,1}x_{6261} \in \{0,1\}
x6263{0,1}x_{6263} \in \{0,1\}
x6353{0,1}x_{6353} \in \{0,1\}
x6362{0,1}x_{6362} \in \{0,1\}
x6364{0,1}x_{6364} \in \{0,1\}
x6454{0,1}x_{6454} \in \{0,1\}
x6463{0,1}x_{6463} \in \{0,1\}
x6465{0,1}x_{6465} \in \{0,1\}
x6555{0,1}x_{6555} \in \{0,1\}
x6564{0,1}x_{6564} \in \{0,1\}
x6566{0,1}x_{6566} \in \{0,1\}
x6656{0,1}x_{6656} \in \{0,1\}
x6665{0,1}x_{6665} \in \{0,1\}
Non-negativity constraints for positional variables
u110u_{11} \ge 0 (Square (1,1))
u120u_{12} \ge 0 (Square (1,2))
u130u_{13} \ge 0 (Square (1,3))
u140u_{14} \ge 0 (Square (1,4))
u150u_{15} \ge 0 (Square (1,5))
u160u_{16} \ge 0 (Square (1,6))
u210u_{21} \ge 0 (Square (2,1))
u220u_{22} \ge 0 (Square (2,2))
u230u_{23} \ge 0 (Square (2,3))
u240u_{24} \ge 0 (Square (2,4))
u250u_{25} \ge 0 (Square (2,5))
u260u_{26} \ge 0 (Square (2,6))
u310u_{31} \ge 0 (Square (3,1))
u320u_{32} \ge 0 (Square (3,2))
u330u_{33} \ge 0 (Square (3,3))
u340u_{34} \ge 0 (Square (3,4))
u350u_{35} \ge 0 (Square (3,5))
u360u_{36} \ge 0 (Square (3,6))
u410u_{41} \ge 0 (Square (4,1))
u420u_{42} \ge 0 (Square (4,2))
u430u_{43} \ge 0 (Square (4,3))
u440u_{44} \ge 0 (Square (4,4))
u450u_{45} \ge 0 (Square (4,5))
u460u_{46} \ge 0 (Square (4,6))
u510u_{51} \ge 0 (Square (5,1))
u520u_{52} \ge 0 (Square (5,2))
u530u_{53} \ge 0 (Square (5,3))
u540u_{54} \ge 0 (Square (5,4))
u550u_{55} \ge 0 (Square (5,5))
u560u_{56} \ge 0 (Square (5,6))
u610u_{61} \ge 0 (Square (6,1))
u620u_{62} \ge 0 (Square (6,2))
u630u_{63} \ge 0 (Square (6,3))
u640u_{64} \ge 0 (Square (6,4))
u650u_{65} \ge 0 (Square (6,5))
u660u_{66} \ge 0 (Square (6,6))

Solving with Pyomo and NetworkX libraries

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 Zip

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

def solve_zip(n:int, m:int, numbered_squares:dict|list, walls:list=None) -> None:

    # Input validation
    if n < 1 or m < 1:
        raise ValueError("The grid dimensions must be equal or greater then 1")

    if not isinstance(n, int) or not isinstance(m, int):
        raise ValueError("The grid dimensions must be integers")

    if len(numbered_squares) > n * m:
        raise ValueError("The number of numbered squares exceeds the amount of vertices in the grid.")

    if len(numbered_squares) < 2 or n * m < 2:
        raise ValueError("The number of numbered squares exceeds the amount of vertices in the grid.")

    if isinstance(numbered_squares, list):
        numbered_squares = {key: value for key, value in enumerate(numbered_squares)}
    elif isinstance(numbered_squares, dict):
        pass
    else:
        raise ValueError("The numbered squares must be a dictionary or a list.")
    
    model = pyo.ConcreteModel()

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

    # Sets
    V = model.Vertices = pyo.Set(initialize=lambda model: [(i, j) for i in I for j in J])
    E = model.Edges = pyo.Set(initialize=lambda model: [
        ((i, j), (i+1, j)) for i in I for j in J if i+1 in I] + [
        ((i, j), (i-1, j)) for i in I for j in J if i-1 in I] + [
        ((i, j), (i, j+1)) for i in I for j in J if j+1 in J] + [
        ((i, j), (i, j-1)) for i in I for j in J if j-1 in J]
    )
    K = model.NumberedVertices = pyo.Set(initialize=numbered_squares.keys(), dimen=2)
    W = model.Walls = pyo.Set(initialize=walls)
    
    # Decision variables
    x = model.x = pyo.Var(E, within=pyo.Binary, initialize=0)
    u = model.u = pyo.Var(V, within=pyo.NonNegativeReals)

    # Parameters
    k = model.k = pyo.Param(V, initialize=numbered_squares, default=0, within=pyo.NonNegativeIntegers)

    # Objective function
    model.obj = pyo.Objective(expr=0)
    
    # Constraints
    model.outgoing_edges_constraints = pyo.Constraint(
        V,
        rule=lambda model, i, j: \
            sum(x[(i,j),w] for w in V if ((i,j),w) in E) == 1 if k[i,j] != len(K) else \
            sum(x[(i,j),w] for w in V if ((i,j),w) in E) == 0
    )
    
    model.incoming_edges_constraints = pyo.Constraint(
        V,
        rule=lambda model, i, j: \
            sum(x[v,(i,j)] for v in V if (v,(i,j)) in E) == 1 if k[i,j] != 1 else \
            sum(x[v,(i,j)] for v in V if (v,(i,j)) in E) == 0
    )
    
    if W is not None:
        model.wall_constraints = pyo.Constraint(
            W,
            rule=lambda model, i, j, r, s: x[i,j,r,s] + x[r,s,i,j] == 0
        )
    
    M = n * m
    
    model.subroute_elimination_constraints = pyo.Constraint(
        E,
        rule=lambda model, i, j, r, s: u[r,s] >= u[i,j] + 1 - M*(1 - x[i,j,r,s])
    )
    
    model.first_square_position_constraint = pyo.Constraint(
        K,
        rule= lambda model, i, j: u[i,j] == 1 if k[i,j] == 1 else pyo.Constraint.Skip
    )
    
    model.ordinal_position_constraints = pyo.Constraint(
        K, K,
        rule= lambda model, i, j, r, s: u[i,j] >= u[r,s] + 1 if k[i,j] == k[r,s] + 1 else pyo.Constraint.Skip
    )
    
    model.last_square_position_constraint = pyo.Constraint(
        K,
        rule= lambda model, i, j: u[i,j] == M if k[i,j] == len(K) else pyo.Constraint.Skip
    )
    
    # Optmization result
    solver = pyo.SolverFactory("gurobi")
    results = solver.solve(model)

    if str(results.Solver.status) == "ok":
        
        G = nx.grid_2d_graph(n,m).to_directed()
        plt.figure(figsize=(3.4, 3.4))
        
        nx.draw(
            G,
            pos= {(i,j): (j,-i) for i, j in G.nodes()},
            with_labels= True,
            labels= {(i-1, j-1): k[i,j] for (i,j) in K},
            arrows=False,
            node_shape="o", # round nodes
            node_size= 1000,
            node_color= ["white" if (i+1,j+1) in K else "#EE5F12" for (i,j) in G.nodes()],
            edge_color= "#EE5F12",
            edgecolors='#EE5F12',
            linewidths= 3,
            width= 35,
            edgelist= [((i-1, j-1), (r-1, s-1)) for i, j, r, s in model.Edges if pyo.value(model.x[i,j,r,s]) == 1]
        )
        plt.show()
    else:
        print("No valid solution was found!")

With the function created, we can pass on the necessary information to solve the game.

numbered_squares = {
    (1,1):  9,
    (1,2): 10,
    (1,3): 11,
    (2,1):  8,
    (2,4): 13,
    (3,1):  7,
    (3,4): 14,
    (3,5): 12,
    (4,2):  6,
    (4,3): 15,
    (4,6): 16,
    (5,3):  5,
    (5,6):  3,
    (6,4):  4,
    (6,5):  1,
    (6,6):  2
}
solve_zip(6,6,numbered_squares)
<Figure size 340x340 with 1 Axes>

As expected, the displayed path satisfies all the rules of Zip No. 166.

Zip game solution. Source: LinkedIn

Figure 4:Zip game solution. Source: LinkedIn


References