VoronoiMesh as a Graph
With IGraph/M, you can use
IGLatticeMesh["Hexagonal", Rectangle[{0, 0}, {2, 4}]]
IGLatticeMesh
first fills the region Rectangle[{0, 0}, {2, 4}]
with lattice points, then places a unit mesh cell at each lattice point. You can use a different region to obtain a different overall shape. Keep in mind that it is not the mesh that is being cropped to this region, but only the points that define the locations of unit cells.
IGMeshGraph[%]
L = 3;
pts = Flatten[Table[{3/2 i, Sqrt[3] j + Mod[i, 2] Sqrt[3]/2}, {i, L + 4}, {j, L + 4}], 1];
mesh0 = VoronoiMesh[pts];
mr0 = DiscretizeGraphics[Select[MeshPrimitives[mesh0, 2],
RegionWithin[Rectangle @@ Transpose[CoordinateBounds[pts]], #] &]];
el0 = MeshCells[mr0, 1] /. Line -> Apply[UndirectedEdge];
vc0 = MeshCoordinates[mr0];
Show[mesh0, Graph[el0, VertexCoordinates -> vc0, EdgeStyle -> Thick]]
Slightly more convenient approach is to provide the coordinate bounds in the second argument of VoronoiMesh
and discretize the interior polygons:
mesh1 = VoronoiMesh[pts, CoordinateBounds[pts]];
mr1 = DiscretizeGraphics[MeshPrimitives[mesh1, {2, "Interior"}]];
el1 = MeshCells[mr1, 1] /. Line -> Apply[UndirectedEdge];
vc1 = MeshCoordinates[mr1];
Show[mesh1,
Graph[el1, VertexCoordinates -> vc1, EdgeStyle -> Thick]]