It just so happens that I found a VERY easy solution to this problem. I use a Flood-Fill technique as follows. First I create a number of random seed locations on the map. Then I use Flood-Fill to "grow" the seeds, randomly. The results very much mirror what was asked for. The code for this is not particularly long. Perhaps one question is, "So, how many seeds should I use?" This will depend on how small/large you would like each region to be. One easy solution is to use a number of partitions as a percentage of the number of hexes/squares in your land mass. For instance: say your land mass is 400 hexes in size and you would like your land mass divided into 10 regions, then simply divide the total size of the land mass (400) by 10 and, thus, create 40 seeds. This is also further easily modified to have a random # of regions (or a random # of regions within a given range, etc...). The following Java code should get you close. Obviously, you will have to fill in some code, but hopefully you get the idea:
private void Assign_Hexes_to_Regions (
final Random RNG,
List <Integer> frontier_hex_IDs,
List <Integer> accompanying_frontier_region_IDs,
final Function <Coords, List <Coords>>
function_all_adjacent_coords
) {
//
// use a Flood-Fill technique to assign EACH Hex to EXACTLY ONE Region
//
while ( frontier_hex_IDs.size() > 0 ) {
//
// Randomly select one of the UNASSIGNED Hexes
//
int random_index = RNG.nextInt( frontier_hex_IDs.size() );
int random_vertex_ID = frontier_hex_IDs.remove( random_index );
int random_region_ID = accompanying_frontier_region_IDs.remove( random_index );
Integer existing_region_ID = this.hex_ID_to_partition_ID.get( random_hex_ID );
if ( existing_region_ID == null ) {
//
// NO Region assigned (yet) to this (Random) Hex
//
this.Assign_Hex_ID_to_Region( random_hex_ID, random_region_ID, frontier_hex_IDs, accompanying_frontier_region_IDs, function_all_adjacent_coords );
} else if ( existing_region_ID != random_region_ID ) {
//
// This Hex was PREVIOUSLY assigned to a DIFFERENT Region. Thus,
// this Hex is at a Region Boundary
//
this.Get_Region( existing_region_ID ).Add_Boundary_Hex_ID( random_hex_ID );
}
}
private void Assign_Hex_ID_to_Region (
final int hex_ID,
final int region_ID,
List <Integer> frontier_hex_IDs,
List <Integer> accompanying_frontier_region_IDs,
final Function <Coords, List <Coords>>
function_all_adjacent_coords
) {
//
// Assigns the Hex to the specified Region
//
this.Set_Region_ID_for_Hex_ID( hex_ID, region_ID );
//
// Add Adjacent Hexes to the Flood-Fill possibilities
//
// note: the Get_All_Adjacent_Coords() function determines if the Coordinates Wrap-Around or not
//
for ( Coords adjacent_vertex_coords : function_all_adjacent_coords.apply( this.space_subset.Get_Space().Get_Coords_from_Vertex_ID( vertex_ID ) ) ) {
if ( this.space_subset.Get_Space().Has_Coords( adjacent_vertex_coords ) ) {
Integer adjacent_hex_ID = this.space_subset.Get_Space().Get_Hex_ID_from_Coords( adjacent_hex_coords );
if ( this.space_subset.Is_in_Subset( adjacent_hex_ID ) ) {
frontier_hex_IDs.add( adjacent_hex_ID );
accompanying_frontier_region_IDs.add( region_ID );
}
//
// do NOT Add the Adjacent Hex if it is OFF on the Land Mass
//
}
//
// do NOT Add the Adjacent Hex if it is NOT on the Map (incl. Wrap-Around)
//
}
}
Here are 2 screenshots of a land mass with 2 different randomly-created regions using the Flood-Fill algorithm.