Here is an answer that provides modular definitions that allow
plotting the play-table and players moves with different options, and
testing for a complete path by a player.
(The function definitions are given in the last section.)
Plotting
This plots the the Hex 8x8 grid and the paths of the X player and Y player:
HexGrid[8, 8, {{1, "a"}, {1, "b"}, {2, "b"}, {3, "b"}, {3, "c"}}, {{5,
8}, {6, 7}, {6, 6}}]
The full signature is:
HexGrid[
nx_Integer, ny_Integer,
xPlayerPath : {{_Integer, _Integer | _String} ...},
yPlayerPath : {{_Integer, _Integer | _String} ...},
opts : OptionsPattern[] ]
Another example same grid and player moves as above, but with different coloring:
HexGrid[8, 8, {{1, 1}, {1, 2}, {2, 2}, {3, 2}, {3, 3}}, {{5, 8}, {6,
7}, {6, 6}}, "CellColor" -> Lighter[Pink],
"XPlayerColor" -> Yellow, "YPlayerColor" -> Green]
Complete path check
The complete path check can be done in several ways. Since OP wants to be able to develop the game with strategies etc. I think graph based definitions would be very useful for the development process.
Using the graph representation of the play-table (see below) the plot function HexGrid
can recognize and mark with a line complete paths.
Find paths:
hgr = HexGraph[8, 8];
xpath = RandomChoice@FindPath[hgr, {1, 2}, {8, 3}, 12, 900];
ypath = Complement[RandomChoice@FindPath[hgr, {2, 1}, {7, 8}, 13, 60], xpath];
Plot Hex play-table and paths:
HexGrid[8, 8, xpath, ypath, "CompletePathColor" -> Cyan, "CompletePathThickness" -> 0.013]
More details for the graph representation
This function call makes the Hex game graph:
hgr = HexGraph[8, 8]
Now let us find a path from side to side for X player, visualize it, verify it recognized as a complete path.
cpath = FindShortestPath[hgr, {1, 2}, {8, 3}];
HighlightGraph[hgr, Subgraph[hgr, cpath]]
HexCompletePathQ[hgr, cpath, "X"]
HexCompletePathQ[8, 8, cpath, "X"]
If we remove some nodes from the path the test is not passed:
HexCompletePathQ[hgr, Most[cpath], "X"]
HexCompletePathQ[hgr, Drop[cpath, {4}], "X"]
(* Out[179]= False
Out[180]= False *)
Another example for Y player:
Definitions
Plotting functions
hexagonPoints = Table[{Cos[i \[Pi]/3], Sin[i \[Pi]/3]}, {i, 0, 5}];
hexagonPoints = RotateLeft[hexagonPoints.RotationMatrix[-\[Pi]/6]];
Clear[HexagonTranslationVector]
HexagonTranslationVector[hexagonPoints_, pInd1_, pInd2_] :=
Block[{v},
v = Mean[{hexagonPoints[[pInd1]], hexagonPoints[[pInd2]]}] -
Mean[hexagonPoints];
2 v
];
Clear[SpreadHexagons]
SpreadHexagons[hexagonPoints_, nx_Integer, ny_Integer] :=
Block[{tv1, tv2, s, h},
{tv1, tv2} = {HexagonTranslationVector[hexagonPoints, 4, 5],
HexagonTranslationVector[hexagonPoints, 5, 6]};
Table[Map[# + (i*tv1 + j*tv2) &, hexagonPoints], {i, 0,
nx - 1}, {j, 0, ny - 1}]
];
Clear[HexGrid]
Options[HexGrid] = {"GridColor" -> Purple,
"CellColor" -> GrayLevel[0.9], "Borders" -> True,
"XPlayerColor" -> Red, "YPlayerColor" -> Blue,
"CompletePathColor" -> White, "CompletePathThickness" -> 0.02};
HexGrid[
nx_Integer, ny_Integer,
xPlayerPath : {{_Integer, _Integer | _String} ...},
yPlayerPath : {{_Integer, _Integer | _String} ...},
opts : OptionsPattern[]] :=
Block[{gridColor, cellColor, bordersQ, xBorderIDs, yBorderIDs,
fullGrid, grid, xPlayerColor, yPlayerColor, cPathColor,
cPathThickness, yRules},
gridColor = OptionValue["GridColor"];
cellColor = OptionValue["CellColor"];
bordersQ = TrueQ[OptionValue["Borders"]];
xPlayerColor = OptionValue["XPlayerColor"];
yPlayerColor = OptionValue["YPlayerColor"];
cPathColor = OptionValue["CompletePathColor"];
cPathThickness = OptionValue["CompletePathThickness"];
xBorderIDs = Range[1, nx];
yBorderIDs = Take[CharacterRange["a", "z"], ny];
fullGrid = SpreadHexagons[hexagonPoints, nx + 2, ny + 2];
grid = fullGrid[[2 ;; nx + 1, 2 ;; ny + 1]];
yRules = Thread[# -> Range[Length[#]]] &@CharacterRange["a", "z"];
Graphics[{
FaceForm[cellColor], EdgeForm[gridColor],
Polygon /@ grid,
If[! bordersQ, Null,
{MapThread[
Text, {yBorderIDs,
Take[Mean /@ fullGrid[[1]], {2, nx + 1}]}],
MapThread[
Text, {yBorderIDs,
Take[Mean /@ fullGrid[[-1]], {2, nx + 1}]}],
MapThread[
Text, {xBorderIDs,
Take[Mean /@ Transpose[fullGrid][[1]], {2, nx + 1}]}],
MapThread[
Text, {xBorderIDs,
Take[Mean /@ Transpose[fullGrid][[-1]], {2, nx + 1}]}]}
],
If[Length[xPlayerPath] == 0,
Null, {FaceForm[xPlayerColor],
Polygon[grid[[Sequence @@ #]]] & /@ (xPlayerPath /. yRules)}],
If[Length[yPlayerPath] == 0,
Null, {FaceForm[yPlayerColor],
Polygon[grid[[Sequence @@ #]]] & /@ (yPlayerPath /. yRules)}],
If[! HexCompletePathQ[nx, ny, xPlayerPath /. yRules, "X"],
Null, {Thickness[cPathThickness], cPathColor,
Line[Mean[grid[[Sequence @@ #]]] & /@ (xPlayerPath /.
yRules)]}],
If[! HexCompletePathQ[nx, ny, yPlayerPath /. yRules, "Y"],
Null, {Thickness[cPathThickness], cPathColor,
Line[Mean[grid[[Sequence @@ #]]] & /@ (yPlayerPath /. yRules)]}]
}, AspectRatio -> Automatic]
];
Complete/winning path check
The variable hexagonPoints
is redefined below in order the code of this sub-section to be independent.
hexagonPoints = Table[{Cos[i \[Pi]/3], Sin[i \[Pi]/3]}, {i, 0, 5}];
hexagonPoints = RotateLeft[hexagonPoints.RotationMatrix[-\[Pi]/6]];
Clear[HexGraph]
HexGraph[nx_Integer, ny_Integer] :=
Block[{nodes},
nodes =
Flatten[Map[Mean, SpreadHexagons[hexagonPoints, nx, ny], {2}],
1];
VertexReplace[
NearestNeighborGraph[
nodes, {All, Norm[nodes[[1]] - nodes[[2]]] 1.01}],
MapThread[
Rule, {nodes, Flatten[Table[{i, j}, {i, nx}, {j, ny}], 1]}]]
];
Clear[HexCompletePathQ]
HexCompletePathQ[nx_Integer, ny_Integer,
path_: {{_Integer, _Integer} ...}, playerID : ("X" | "Y")] :=
HexCompletePathQ[HexGraph[nx, ny], path, playerID];
HexCompletePathQ[hgr_, path_: {{_Integer, _Integer} ...},
playerID : ("X" | "Y")] :=
Block[{sgr, cs, hvs},
If[Length[path] == 0, Return[False]];
sgr = Subgraph[hgr, path];
cs = ConnectedComponents[sgr];
sgr = Subgraph[hgr,
cs[[Position[Length /@ cs, Max[Length /@ cs]][[1, 1]]]]];
hvs = VertexList[hgr];
If[playerID == "X",
Length[Intersection[VertexList[sgr], Cases[hvs, {1, _}]]] > 0 &&
Length[
Intersection[VertexList[sgr],
Cases[hvs, {Max[hvs[[All, 1]]], _}]]] > 0,
(* playerID == "Y"*)
Length[Intersection[VertexList[sgr], Cases[hvs, {_, 1}]]] > 0 &&
Length[
Intersection[VertexList[sgr],
Cases[hvs, {_, Max[hvs[[All, 2]]]}]]] > 0
]
];