My approach - standard backtrack. I represented the board as a 15 by 21 rectangle, and the two types of cells (parity) as 0 and 1. For each orientation of each piece, I had to track the locations of the cells it would fill, and also their parity. I followed a set scanning order, going across the rows, bottom to top, from right to left, find the first unfilled cell, scan the randomized list of pieces and orientations to find the next piece of proper parity which would fit, and testing to see if holes were created, and also if the piece touched the top, to see that any regions created were not divisible by 5. When no more placements were possible, lift the last piece and continue. Occasionally a region would occur which was fillable only by pieces already in place. The solver would spin its wheels trying to fill the rest of that row, hitting the bad place, then backtracking. If this happened early on, too much time would be required to backtrack far enough due to the larger number of possibilities. I decided not to program a check for this, since most of the time the solver ran very quickly up to the 57-59 pieces placed range, and getting past bad areas was very fast due to the small number of pieces left to try. Also each time I restarted, the run was different due to the randomization.