A raw data pattern can have large blank areas or runs that confuse a scanner, so QR flips modules in a regular pattern to break them up. There are eight such mask patterns; today you write all eight conditions and apply one to the data region.
Define the eight mask conditions and apply a mask by flipping data modules where its condition holds.
The unmasked data grid is correct but often ugly: a stretch of zeros makes a big light patch, and a scanner can lose its place in it. A mask fixes this by flipping modules in a fixed geometric pattern, breaking up runs and balancing dark and light. There are exactly eight masks, numbered 0 to 7, each defined by a boolean condition over a module’s coordinates. Where the condition is true, that module is inverted.
Crucially, a mask applies only to data modules - finder patterns, timing, the dark module, and the reserved format area are never masked, because their fixed shapes must survive. So applyMask walks the placeable modules only and flips those whose condition holds. Masking is reversible (flip twice and you are back), which is exactly how a scanner undoes it after reading the mask number from the format information. You do not pick a mask yet: the next four lessons build the scoring that decides which of the eight leaves the cleanest symbol.
// Condition is true -> flip that data module.var masks = []func(r, c int) bool{func(r, c int) bool { return (r+c)%2 == 0 },func(r, c int) bool { return r%2 == 0 },func(r, c int) bool { return c%3 == 0 },func(r, c int) bool { return (r+c)%3 == 0 },func(r, c int) bool { return (r/2+c/3)%2 == 0 },func(r, c int) bool { return (r*c)%2+(r*c)%3 == 0 },func(r, c int) bool { return ((r*c)%2+(r*c)%3)%2 == 0 },func(r, c int) bool { return ((r+c)%2+(r*c)%3)%2 == 0 },}