Visualize Inclusion-Exclusion
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