# 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 as a list of 4-tuples (x1, y1, x2, y2) or (x1, x2, y1, y2) (or any permutation thereof) with x1 < x2 && y1 < y2 for each. 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).

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 , so the objective is to have the shortest code. Happy golfing!

• x-axis extends rightwards and y-axis extends downward from the top-left corner? – user202729 Oct 23 '17 at 13:41
• @user202729 In test cases, yes (actually ambiguous) but you may use either as long as you're consistent – HyperNeutrino Oct 23 '17 at 13:43
• @dzaima Yup. [...] – HyperNeutrino Oct 23 '17 at 13:45
• So, x2 and y2 are the respective first coordinates not part of the rectangle? – Felix Palmen Oct 23 '17 at 14:18
• @FelixPalmen ? I don't get what you mean – HyperNeutrino Oct 23 '17 at 14:43

# Python 2, 218192189185158154 147 bytes

def f(l):_,_,a,b=map(range,map(max,zip(*l)));print'\n'.join(''.join((' '+'#.'*len(l))[sum((x<=i<X)*(y<=j<Y)for x,y,X,Y in l)]for i in a)for j in b)


Try it online!

# 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<startaddress>,<x1>,<y1>,<x2>,<y2>[,<x1>,<y1>,<x2>,<y2>[,...]] 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 ( -> '#')
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 -> repeat E8 INX ; next y E4 22 CPX$22             ; equals y2?
D0 E9       BNE .rowloop        ; no -> 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


# Python 2, 181 bytes

l=input()
_,_,x,y=map(max,zip(*l))
m=eval([[32]*x]*y)
for v,w,x,y in l:
for i in range(v,x):
for j in range(w,y):
m[i][j]=max(m[i][j]^1,34)
for n in m:print''.join(map(chr,n))


Try it online!

# Charcoal, 40 bytes

ＷＳ«≔Ｉ⪪ι ιＦ…§ι⁰§ι²«Ｊκ§ι¹ＵＭＫＤ⁻§ι³§ι¹↓§10Σλ


Try it online! Link is to verbose version of code. Will be 6 bytes shorter once @ASCII-only fixes a bug in Charcoal. Takes input as a newline-terminated list of space-separated list of co-ordinates. Explanation:

ＷＳ«


Loop over each line of input until a blank line is reached.

≔Ｉ⪪ι ι


Split the line into a list of co-ordinates.

Ｆ…§ι⁰§ι²«


Loop over all the X co-ordinates.

Ｊκ§ι¹


ＵＭ


Map over each of...

ＫＤ⁻§ι³§ι¹↓


... all the cells in the column...

§10Σλ


... the new value is 0 if they contain 1, otherwise 1. Edit: Soon after writing this, Charcoal changed the behaviour of ¬ so that Ｉ¬Σλ works here to save 1 byte.

• :| did i mess something up tio.run/… – ASCII-only Oct 26 '17 at 13:46
• @ASCII-only Bug in my workaround - I can print an \n instead I guess... – Neil Oct 26 '17 at 15:31

# C (gcc), 205 bytes

x[999][999];a;b;c;d;j;k;l;m;n;main(i){for(;scanf("%d %d %d %d",&a,&b,&c,&d)>3;m=d>m?d:m,n=c>n?c:n)for(i=b;i<d;++i)for(j=a;j<c;++j)x[i][j]=x[i][j]^2|1;for(;k<n||++l<(k=0,puts(""),m);putchar(x[l][k++]+32));}


Try it online!

# R, 196 189 bytes

m=matrix
x=m(scan(file("stdin")),4)
y=m(0,max(x[3,]),max(x[4,]))
n=ncol(x)
while(n){z=x[,n]
i=z[1]:z[3]
j=z[2]:z[4]
y[i,j]=y[i,j]+1
n=n-1}
i=!y
y=y%%2+1
y[i]=' '
cat(rbind(y,'\n'),sep='')


Try it online!

The code reads input as stdin, arranged as a x1 y1 x2 y2 tuple, where x is the column and y is the row. I am using 1 and 2 for the overlap levels, where 1 represents an even level.

Saved 7 bytes thanks to user2390246.

• A few ideas for golfing this down: 1. Is there any need to transform your matrix x? 2. Use nrow (or ncol if not transformed) instead of dim(x)[1] 3. You don't need to define i=y>0 as you only use it once. – user2390246 Oct 25 '17 at 10:33
• 4. Initialise the matrix to -1 and then just use y=y%%2 and y[y<0]=" ". – user2390246 Oct 25 '17 at 10:38
• Thank you. I included suggestion 1 and 2. Suggestions 3 and 4 would not work because: i=y>0 is used to store the levels prior to applying the modulus, and the modulus should not be sign preserving. However, that gave me the idea to use the implicit R convention that 0=FALSE, and save two extra bytes. :) – NofP Oct 25 '17 at 21:21