Visualize Inclusion-Exclusion Inclusion-Exclusion lets you calculate the sizes of some unions and intersections between sets knowing some of the other values. I won't explain it exactly, but your challenge is to visualize inclusion-exclusion on a Venn Diagram.

Because I'm nice, you'll be using rectangles, not circles.

You will be given a list of rectangles denoted by top-left and bottom-right corner coordinates in any reasonable format (list of 4-tuples, list of pairs of pairs, list of pairs, etc). You can assume that all coordinates are non-negative and within your language's (reasonable) number range (please specify what it is if it's less than 128). You can choose to be left-inclusive or left-exclusive and right-inclusive or right-exclusive. Regardless of your chosen format, you can assume all rectangles are at least 1x1.

Then, you are to draw out each rectangle on the screen (ASCII canvas) using a single non-whitespace character k, which is yours to choose.

However, whenever two rectangles overlap, the overlapping area shall be drawn with another non-whitespace character l != k, also yours to choose.

Whenever three rectangles overlap, the overlapping area should be drawn with k, and for an odd number of rectangles covering, k, and an even number, l.

The background should be single whitespaces (0x20).

Test Cases (k = "#", l = ".")

0 0 9 9
1 1 10 10
2 2 11 11

#########  
#........# 
#.#######.#
#.#######.#
#.#######.#
#.#######.#
#.#######.#
#.#######.#
#.#######.#
 #........#
  #########

1 1 3 3
2 2 4 4


 ## 
 #.#
  ##

1 1 9 9
2 2 8 8
3 3 7 7


 ########
 #......#
 #.####.#
 #.####.#
 #.####.#
 #.####.#
 #......#
 ########


Notes


Leading spaces and newlines (which occur if the minimum coordinate isn't 0, 0) must be present
Any trailing spaces and newlines are allowed to a reasonable extent (i.e. don't trail like 100000000 newlines, that's just annoying)
x- and y- axes can face either way but you must be consistent and specify which (default is x- right and y- down)
coordinates can be 0-, 1-, or 2- indexed.


Reference Proton Implementation

This is code-golf, so the objective is to have the shortest code. Happy golfing!
6502 machine code routine (C64), 57 bytes

20 44 E5 A0 03 84 FB 20 9B B7 A4 FB 96 22 C6 FB 10 F5 85 FC A6 24 20 F0 E9 A4
25 B1 D1 09 01 49 02 91 D1 C8 C4 23 D0 F3 E8 E4 22 D0 E9 A9 2C C5 FC F0 D0 A5
C6 F0 FC C6 C6 4C 44 E5


This is position-independent code, put it somewhere in RAM and use the correct start address calling it with sys.

Online demo (start address $C000 / 49152).

Usage: sys&lt;startaddress&gt;,&lt;x1&gt;,&lt;y1&gt;,&lt;x2&gt;,&lt;y2&gt;[,&lt;x1&gt;,&lt;y1&gt;,&lt;x2&gt;,&lt;y2&gt;[,...]]

Example: sys49152,0,0,9,9,1,1,10,10,2,2,11,11

On reasonable number ranges: The natural range on this 8-bit machine is [0-255], and the program will accept this as parameters. But the C64 screen only has 40 columns and 25 rows, therefore limiting the reasonable range to [0-40] for x values and [0-25] for y values. Using other values will have unpredictable behavior.



commented disassembly listing:

20 44 E5    JSR $E544           ; clear screen
 .mainloop:
A0 03       LDY #$03            ; index for reading coordinates
84 FB       STY $FB
 .inputrect:
20 9B B7    JSR $B79B           ; read 8bit value from parameter
A4 FB       LDY $FB
96 22       STX $22,Y           ; and store to $22-$25
C6 FB       DEC $FB
10 F5       BPL .inputrect      ; parameter reading loop
85 FC       STA $FC             ; store last character
A6 24       LDX $24             ; load y1
 .rowloop:
20 F0 E9    JSR $E9F0           ; get pointer to screen row in $d1/$d2
A4 25       LDY $25             ; load x1
 .colloop:
B1 D1       LDA ($D1),Y         ; load character at screen position
09 01       ORA #$01            ; set bit 0 ( -&gt; '#')
49 02       EOR #$02            ; toggle bit 1 (toggle between '#' and '!' )
91 D1       STA ($D1),Y         ; store character at screen position
C8          INY                 ; next x
C4 23       CPY $23             ; equals x2?
D0 F3       BNE .colloop        ; no -&gt; repeat
E8          INX                 ; next y
E4 22       CPX $22             ; equals y2?
D0 E9       BNE .rowloop        ; no -&gt; repeat
A9 2C       LDA #$2C            ; load ','
C5 FC       CMP $FC             ; compare with last character from parsing
F0 D0       BEQ .mainloop       ; if ',', repeat reading coordinates
 .waitkey:
A5 C6       LDA $C6             ; load input buffer size
F0 FC       BEQ .waitkey        ; and repeat until non-empty
C6 C6       DEC $C6             ; set back to empty
4C 44 E5    JMP $E544           ; clear screen