Can You Tile a Hexagon?

Here is the 6/26/2026 Fiddler on the Proof puzzle verbatim.

I’m redoing my kitchen floor using rhombus-shaped tiles composed of two congruent equilateral triangles. One such tile is shown in blue below. How many distinct ways can I use these to tile the outlined region below, which consists of 24 equilateral triangles arranged in a regular hexagon?

Since general functions will be used, we’ll be addressing the extra credit portion at the same time, which involves tiling the hexagon with 54 triangles.

Solution

Let’s number the triangles within the hexagon left-to-right, top-to-bottom giving preference to the upside-down triangles first (the ones pointing down). Here is a picture for reference.

Now, let’s build a function that will create a list of all the possible pairings. We want 1 to pair with 3 or 4, 2 to pair with 4 or 5, etc.

# for side length 1 there are 6 triangles inside a hexagon. For side length 2,
# there are 24, and in general, 6 * (side length)^2. 
make_hex_list <- function(side) {
  sqrt3 <- sqrt(3)
  
  point <- function(i, j) {
    c(i + j / 2, sqrt3 * j / 2)
  }
  
  hex <- rbind(
    c( side, 0),
    c( side / 2,  sqrt3 * side / 2),
    c(-side / 2,  sqrt3 * side / 2),
    c(-side, 0),
    c(-side / 2, -sqrt3 * side / 2),
    c( side / 2, -sqrt3 * side / 2)
  )
  
  inside_hex <- function(p) {
    tol <- 1e-9
    
    for (k in 1:6) {
      a <- hex[k, ]
      b <- hex[ifelse(k == 6, 1, k + 1), ]
      
      cross <- (b[1] - a[1]) * (p[2] - a[2]) -
        (b[2] - a[2]) * (p[1] - a[1])
      
      if (cross < -tol) return(FALSE)
    }
    
    TRUE
  }
  
  triangles <- list()
  
  for (i in seq(-2 * side - 2, 2 * side + 2)) {
    for (j in seq(-2 * side - 2, 2 * side + 2)) {
      tri1 <- rbind(point(i, j), point(i + 1, j), point(i, j + 1))
      tri2 <- rbind(point(i + 1, j + 1), point(i + 1, j), point(i, j + 1))
      
      for (tri in list(tri1, tri2)) {
        center <- colMeans(tri)
        
        if (inside_hex(center)) {
          triangles[[length(triangles) + 1]] <- list(
            vertices = tri,
            center = center
          )
        }
      }
    }
  }
  
  centers <- do.call(rbind, lapply(triangles, `[[`, "center"))
  
  # Number top to bottom, left to right
  ord <- order(-centers[, 2], centers[, 1])
  triangles <- triangles[ord]
  
  vertex_key <- function(v) {
    paste(round(v[1], 10), round(v[2], 10), sep = ",")
  }
  
  edge_key <- function(a, b) {
    paste(sort(c(vertex_key(a), vertex_key(b))), collapse = "|")
  }
  
  edge_to_tri <- new.env(parent = emptyenv())
  
  for (id in seq_along(triangles)) {
    v <- triangles[[id]]$vertices
    
    edges <- c(
      edge_key(v[1, ], v[2, ]),
      edge_key(v[2, ], v[3, ]),
      edge_key(v[3, ], v[1, ])
    )
    
    for (e in edges) {
      old <- if (exists(e, edge_to_tri, inherits = FALSE)) {
        get(e, edge_to_tri)
      } else {
        integer(0)
      }
      
      assign(e, c(old, id), edge_to_tri)
    }
  }
  
  adj <- vector("list", length(triangles))
  
  for (e in ls(edge_to_tri)) {
    ids <- get(e, edge_to_tri)
    
    if (length(ids) == 2) {
      adj[[ids[1]]] <- c(adj[[ids[1]]], ids[2])
      adj[[ids[2]]] <- c(adj[[ids[2]]], ids[1])
    }
  }
  
  lapply(adj, sort)
}

Hex24 <- make_hex_list(2)
Hex54 <- make_hex_list(3)

head(Hex24)
## [[1]]
## [1] 3 4
## 
## [[2]]
## [1] 4 5
## 
## [[3]]
## [1] 1 6
## 
## [[4]]
## [1] 1 2 7
## 
## [[5]]
## [1] 2 8
## 
## [[6]]
## [1]  3  9 10

Now, a function that counts the unique tiling. When 1 pairs with 3, say, then 3 is disregarded in the list, and 1 is removed as an option for 4, and 3 is removed as an option for 6. This function methodically counts eace way you can pair the entire list of numbers.

# Input the hexagon lists from above into this function to count the tilings. 
count_tilings <- function(pair_list) {
  n <- length(pair_list)
  
  # Make adjacency symmetric, just in case the input list misses reverse links
  adj <- lapply(seq_len(n), function(i) integer(0))
  
  for (i in seq_len(n)) {
    for (j in pair_list[[i]]) {
      adj[[i]] <- union(adj[[i]], j)
      adj[[j]] <- union(adj[[j]], i)
    }
  }
  
  cache <- new.env(parent = emptyenv())
  
  count_from <- function(remaining) {
    if (length(remaining) == 0) return(1)
    if (length(remaining) %% 2 == 1) return(0)
    
    key <- paste(remaining, collapse = ",")
    if (exists(key, envir = cache, inherits = FALSE)) {
      return(get(key, envir = cache))
    }
    
    # Choose a remaining triangle with the fewest available partners
    partner_counts <- sapply(remaining, function(i) {
      sum(adj[[i]] %in% remaining)
    })
    
    i <- remaining[which.min(partner_counts)]
    possible_partners <- intersect(adj[[i]], remaining)
    
    total <- 0
    
    for (j in possible_partners) {
      next_remaining <- setdiff(remaining, c(i, j))
      total <- total + count_from(next_remaining)
    }
    
    assign(key, total, envir = cache)
    total
  }
  
  count_from(seq_len(n))
}

count_tilings(Hex24)
## [1] 20
count_tilings(Hex54)
## [1] 980

Hence, we have 20 ways we can tile the 24-triangle hexagon and 980 ways to tile the 54-triangle hexagon.

Here’s a fun gif that shows the 20 different tilings for the 24 triangle hexagon. Please use at your leisure.