previndexinfonext

code guessing, round #53 (completed)

started at ; stage 2 at ; ended at

specification

ever written funciton? please parse a box drawing. submissions may be written in any language.

introduction

this challenge is a decision problem. your goal, given a "drawing" (a string consisting of Unicode box-drawing characters) is to determine whether or not it follows the following rules.

inputs always consist exclusively of the following characters, in addition to spaces and newlines:

─│┌┐└┘├┤┬┴

the drawings you are looking for consist of "boxes", simple rectangles, connected to each other by lines. it should look like this:

┌──────┐
└┬──┬──┘    ┌───────┐
 │  │       │       │
 │  └───────┤       │
 └────┐     └───┬───┘
    ┌─┴──┐     ┌┘
    │    │    ┌┘
    │    ├┐   └────┐
    └────┘└────────┘

maybe I'm getting ahead of myself? let's start at the beginning. this is a box.

┌──────┐
│      │
│      │
│      │
└──────┘ 

boxes

boxes can have any dimensions, but they always have to be perfect rectangles, so this is not a box:

┌──────┐
│      │
│      └───┐
│          │
└──────────┘

boxes can get very close:

┌──────┐┌────┐
│      ││    │
└──────┘└────┘

but they can't overlap like this:

┌──────┬────┐
│      │    │
└──────┴────┘
     ┌────┐
┌────┼────┘
└────┘

they can be very large and very small.

┌──────────────────────────────────────────┐
│                                          │
│                                          │
│                                          │
│                                          │
│                                          │         ┌┐
│                                          │         └┘
│                                          │
│                                          │
│                                          │
│                                          │
│                                          │
└──────────────────────────────────────────┘

but can't contain each other (or anything that isn't empty space):

┌──────────────────────────────────────────┐
│                                          │
│                                          │
│       ┌┐        ┌┐     ┌───────┐         │
│       ││┌┐      ││     │┌─────┐│         │
│       ││└┘┌┐    ││     ││     ││         │
│       ││  └┘┌┐  ││     ││     ││         │
│       ││    └┘┌┐││     ││     ││         │
│       ││      └┘││     ││     ││         │
│       ││        ││     │└─────┘│         │
│       └┘        └┘     └───────┘         │
│                                          │
└──────────────────────────────────────────┘

boxes shouldn't be partially formed or otherwise broken. none of these are boxes:

┌──────┐          ┌───────
│      │          │      │
│                 │      │
└──────┘          └──────┘

         ┌──────┐
         │      │
         │      ┤
         └──────┘

lines

now that you know all about boxes, let's talk about lines.

if you have two boxes next to other, you can draw a line between them. let's give it a go!

┌────────┐        ┌────────┐
│        │        │        │
│        ├────────┤        │
│        │        │        │
└────────┘        └────────┘

holy fuck. can we add another one?

    ┌──────────────────┐
┌───┴────┐        ┌────┴───┐
│        │        │        │
│        ├────────┤        │
│        │        │        │
└────────┘        └────────┘

no, we can't! that would violate the golden rule: no two boxes can have more than one line between them.

okay, fine. I'll put another box below it and connect that, like this:

┌────────┐        ┌────────┐
│        │        │        │
│        ├────────┤        │
│        │        │        │
└────────┤        └────────┘
         │
         ├────────┐
         │        │
         │        │
         │        │ 
         └────────┘

wrong again! this violates the goldener rule. lines can't connect to boxes on their corners. why not? because if we added another line to this drawing...

┌────────┐        ┌────────┐
│        │        │        │
│        ├────────┤        │
│        │        │        │
└────────┤        ├────────┘
         │        │ <-- oh fuck
         ├────────┤
         │        │
         │        │
         │        │ 
         └────────┘

it creates what appears to be another box out of the lines! also it looks like a mouse this box looks like it's overlapping the other 3 boxes, so a naive program might think that it wasn't a valid drawing. for this reason, we're helping the players out and forbidding any instance of a line connecting to a corner.

lines are allowed to meander, but they shouldn't cross over other lines, trail off or split. it has to start at a box and reach another box unimpeded.

here are some non-lines:

┌┐     ┌┐     ┌┐     ┌┐
││     ││     ││     ││
│├──┴──┤│     │├──┐  │├─┐
││     ││     ││  │  ││ │
└┘     └┘     └┘  │  └┘ │
                  │     │
┌┐     ┌┐     ┌┐  │  ┌┐ │
││     ││     ││  │  ││ │
│├─────││     │├──┼──┤│ │
││     ││     ││  │  ││ │
└┘     └┘     └┘  │  └┘ │
                  └─────┘

the definition

a valid box drawing is a drawing consisting of any number of valid boxes and any number (but obviously not more than 3 times the number of boxes minus 6) of valid lines connecting them. it does not have to be fully connected; there may be boxes with no connections. the diagram may also be completely empty, consisting only of spaces. there must not be any non-whitespace characters in the drawing than other the ones constituting the objects.

the challenge

your challenge, given a string with lines of equal length representing a grid of box-drawing characters, is to decide whether or not it is a valid box drawing according to the above rules. as any language is allowed, there is no fixed API.

results

  1. 👑 luatic +4 -0 = 4
    1. LyricLy
    2. taswelll
    3. Dolphy
    4. JJRubes (was cdr sa)
    5. cdr sa (was kimapr)
    6. olus2000
    7. kimapr (was JJRubes)
  2. Dolphy +5 -2 = 3
    1. LyricLy
    2. taswelll
    3. JJRubes (was luatic)
    4. cdr sa
    5. kimapr
    6. olus2000
    7. luatic (was JJRubes)
  3. LyricLy +5 -4 = 1
    1. taswelll
    2. Dolphy
    3. kimapr (was luatic)
    4. cdr sa
    5. luatic (was kimapr)
    6. olus2000
    7. JJRubes
  4. taswelll +4 -4 = 0
    1. LyricLy
    2. luatic (was Dolphy)
    3. cdr sa (was luatic)
    4. Dolphy (was cdr sa)
    5. kimapr
    6. olus2000
    7. JJRubes
  5. JJRubes +2 -2 = 0
    1. luatic (was LyricLy)
    2. cdr sa (was taswelll)
    3. LyricLy (was Dolphy)
    4. taswelll (was luatic)
    5. Dolphy (was cdr sa)
    6. kimapr
    7. olus2000
  6. cdr sa +2 -4 = -2
    1. luatic (was LyricLy)
    2. Dolphy (was taswelll)
    3. JJRubes (was Dolphy)
    4. taswelll (was luatic)
    5. kimapr
    6. olus2000
    7. LyricLy (was JJRubes)
  7. kimapr +2 -4 = -2
    1. LyricLy
    2. olus2000 (was taswelll)
    3. luatic (was Dolphy)
    4. JJRubes (was luatic)
    5. cdr sa
    6. Dolphy (was olus2000)
    7. taswelll (was JJRubes)
  8. olus2000 +2 -6 = -4
    1. kimapr (was LyricLy)
    2. taswelll
    3. LyricLy (was Dolphy)
    4. Dolphy (was luatic)
    5. cdr sa
    6. JJRubes (was kimapr)
    7. luatic (was JJRubes)

entries

you can download all the entries

entry #1

written by LyricLy
submitted at
1 like

guesses
comments 0

post a comment


yeah.py Unicode text, UTF-8 text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import itertools
from collections import defaultdict

RIGHT = (1, 0)
DOWN = (0, 1)
LEFT = (-1, 0)
UP = (0, -1)

LINES = {
    " ": set(),
    "─": {LEFT, RIGHT},
    "│": {UP, DOWN},
    "┌": {RIGHT, DOWN},
    "┐": {LEFT, DOWN},
    "└": {UP, RIGHT},
    "┘": {UP, LEFT},
    "├": {UP, RIGHT, DOWN},
    "┤": {UP, LEFT, DOWN},
    "┬": {LEFT, DOWN, RIGHT},
    "┴": {UP, LEFT, RIGHT},
}

def onward(p, d):
    return p[0]+d[0], p[1]+d[1]

def behind(d):
    return -d[0], -d[1]

class Drawing:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.grid = defaultdict(set)

    def points(self):
        return itertools.product(range(self.width), range(self.height))

    def has(self, at, d):
        return d in self.grid[at]

    def erase(self, at, d):
        self.grid[at].discard(d)

    def area_is_empty(self, left, right, top, bottom):
        for x in range(left, right+1):
            for y in range(top, bottom+1):
                if self.grid[x, y]:
                    return False
        return True

    @classmethod
    def parse(cls, s):
        lines = s.split("\n")
        new = cls(max(map(len, lines)), len(lines))
        for y, row in enumerate(lines):
            for x, c in enumerate(row):
                new.grid[x, y] = LINES[c].copy()
        return new 

    def __repr__(self):
        lines = []
        for y in range(self.height):
            lines.append("")
            for x in range(self.width):
                for k, v in LINES.items():
                    if v == self.grid[x, y]:
                        lines[-1] += k
                        break
        return "\n".join(lines)

    def __bool__(self):
        return not self.area_is_empty(0, self.width, 0, self.height)

class Box:
    def __init__(self, left, right, top, bottom):
        assert left <= right and top <= bottom
        self.left = left
        self.right = right
        self.top = top
        self.bottom = bottom

    def sides(self):
        # these ranges should be fully exclusive to avoid the literal "corner cases"
        for x in range(self.left+1, self.right):
            yield (x, self.top), UP
            yield (x, self.bottom), DOWN
        for y in range(self.top+1, self.bottom):
            yield (self.left, y), LEFT
            yield (self.right, y), RIGHT

    def __repr__(self):
        return f"Box(left={self.left}, right={self.right}, top={self.top}, bottom={self.bottom})"

def yield_side(drawing, at, d):
    to_yield = []
    while drawing.has(at, d):
        to_yield.append((at, d))
        at = onward(at, d)
        to_yield.append((at, behind(d)))
        if not drawing.has(at, behind(d)):
            return None, []
    return at, to_yield

def consume_box(drawing, at):
    to_consume = []
    ats = []
    for d in (RIGHT, DOWN, LEFT, UP):
        ats.append(at)
        at, l = yield_side(drawing, at, d)
        if not l:
            return None
        to_consume.extend(l)
    box = Box(ats[0][0], ats[2][0], ats[0][1], ats[2][1])
    if at != ats[0] or not drawing.area_is_empty(box.left+1, box.right-1, box.top+1, box.bottom-1):
        return None
    for p, d in to_consume:
        drawing.erase(p, d)
    return box

def yield_line(drawing, at, d):
    segments = []
    while True:
        b = behind(d)
        segments.append((at, b))
        if not drawing.has(at, b):
            return segments
        for x in (LEFT, RIGHT, DOWN, UP):
            if x == b:
                continue
            if drawing.has(at, x):
                at = onward(at, x)
                d = x
                break
        else:
            return segments

def entry(s):
    drawing = Drawing.parse(s)

    boxes = []
    for point in drawing.points():
        if box := consume_box(drawing, point):
            boxes.append(box)

    connections = set()
    for box in boxes:
        for at, d in box.sides():
            if not drawing.has(at, d):
                continue
            line = yield_line(drawing, onward(at, d), d)
            for box2 in boxes:
                if (box, box2) in connections or (box2, box) in connections or box == box2:
                    continue
                if line[-1] not in list(box2.sides()):
                    continue
                connections.add((box, box2))
                drawing.erase(at, d)
                for p, back in line:
                    drawing.erase(p, back)
                    drawing.erase(p, behind(back))
                break

    # if we deleted everything, it's correct
    return not drawing

entry #2

written by taswelll
submitted at
1 like

guesses
comments 0

post a comment


entry.ijs Unicode text, UTF-8 text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
map=:(ucp;._2~LF&=)freads'in.txt'

show=: [:echo*{"0 1 map,"0{.@":"0  NB. show matrices on top of map

NB. point down, right, up, left
'pd pr pu pl'=:p=:map e."_ 1]4 6$ucp'┐│┌┬┤├┌─└├┴┬└│┘┴├┤┘─┐┤┴┬'

assert ((0,pd)-:pu,0), (0,.pr)-:pl,.0  NB. check that lines are well connected

'c1 c2 c3 c4'=:(*"2~1=+/)turns=:(4$pr,:pl)*.2#pd,:pu NB. find possible corners
ci1=:(*+/\&.,)c1                                     NB. give id to every topleft corner

NB. find corresponding corners, gradually removing non-boxes
ci2=:(>./\ "1 ci1)*c2*(-[:>./\ @}:"1 0:,. (pl>pr)*])+/\ "1   c1   NB. top right
ci4=:(>./\    ci2)*c4*(-[:>./\ @}:   0 ,  (pu>pd)*])+/\    *ci2   NB. bot right
ci3=:(>./\."1 ci4)*c3*(-[:>./\.@}."1 0:,.~(pl<pr)*])+/\."1 *ci4   NB. bot left
ci1=:(>./\.   ci3)*c1*(-[:>./\.@}.   0 ,~ (pu<pd)*])+/\.   *ci3   NB. top left

NB. reassign IDs, now that we are sure that these are boxes (this is probably useless)
'i1 i2 i3 i4'=:(0,~.#~,ci1)(#@[|i.)ci1,ci2,ci3,:ci4

NB. check that corners match (this should always work, i think)
assert ((i1,.i2)-:&(+/)i3,.i4), (i1,i3)-:&:(+/"1)i2,i4

echo 'boxes:'
cov=: -&(+/\)|.!.0                     NB. 0 0 2 0 0 0 cov 0 0 0 0 2 0 <--> 0 0 2 2 2 0
show area=:(i1 cov i3)cov"1(i2 cov i4) NB. boxes including borders. print because pretty
inside   =:(i4 cov i2)cov"1(i3 cov i1) NB. i am very happy that this works
border   =:area-inside

assert 1>:(i1 cov&:*i3)cov"1(i2 cov&:*i4) NB. check for no box overlaps
assert -.inside*.+./turns                 NB. check that the boxes are empty
assert border>:1<+/turns                  NB. check all splits are in box borders

NB. remove boxes for pathfinding. "edges" is ed,er,eu,:el where er is "can walk from right"
sidelr=:area+(i2 cov i4)cov"1(i1 cov i3)
sideud=:area+(i3 cov i1)cov"1(i4 cov i2)
edges=:p>4$sidelr,:sideud

NB. l: starting positions of all lines with IDs. lid: map from line ID -> box no
'lid l'=:((#~*)@:,;(*+/\&.,)@:*)border*1<+/turns

echo 'lines (shown for your viewing pleasure):'
connects=:3 :0 i.0 0
while. +./,*l do. show l
    rot=.l,edges*l|.~"2 1+.0j1^i.4                  NB. rot has 5 items: original,rotated d,r,u,l
    y=.y,con=./:~@~.@-.&0"1(#~2<#@~."1),/1 2 0|:rot NB. new connections between different lines
    l=:(*[-.@e.,@con)>./rot                         NB. combine rot, removing connections
end.
/:~"1{&lid<:~.y
)
NB. check no double connections or self-connections between boxes
assert ((-:~.),[:*./~:/"1) connects
echo 'Yes'

entry #3

written by Dolphy
submitted at
1 like

guesses
comments 0

post a comment


entry.py Unicode text, UTF-8 text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
from typing import Tuple
from dataclasses import dataclass
from enum import Enum

class Direction(Enum):
    RIGHT = 0
    UP = 1
    LEFT = 2
    DOWN = 3

@dataclass
class BoxInfo:
    x: int
    y: int
    width: int
    height: int

@dataclass
class ConnectionInfo:
    x: int
    y: int
    direction: Direction
    box_index: int

VALID_CHARACTERS = '─│┌┐└┘├┤┬┴ \n'

def get_box_info(input: list[str], x: int, y: int) -> BoxInfo | None | bool:
    if input[y][x] != '┌':
        return None

    width = 1
    height = 1
    try:
        while input[y][x + width] in ('─', '┴'):
            width += 1
    except:
        pass
    try:
        while input[y + height][x] in ('│', '┤'):
            height += 1
    except:
        pass
    try:
        if input[y + height][x] in ('├', '┬', '┤') or input[y][x + width] in ('├', '┬', '┤') or input[y + height][x + width] in ('├', '┬', '┤'):
            return False
        if input[y + height][x] != '└' or input[y][x + width] != '┐':
            return None
    except:
        return None

    for i in range(width):
        if input[y + height][x + i] not in ('└', '─', '┬', '┘'):
            return False
    
    for i in range(height):
        if input[y + i][x + width] not in ('┐', '│', '├', '┘'):
            return False
    return BoxInfo(x, y, width + 1, height + 1)

def find_connections(input: list[str], box: BoxInfo, box_index) -> list[ConnectionInfo]:
    x, y = box.x, box.y
    w, h = box.width, box.height

    result = []

    for i in range(w):
        if input[y][x + i] == '┴':
            result.append(ConnectionInfo(x + i, y, Direction.UP, box_index))
        if input[y + h - 1][x + i] == '┬':
            result.append(ConnectionInfo(x + i, y + h - 1, Direction.DOWN, box_index))

    for i in range(h):
        if input[y + i][x] == '┤':
            result.append(ConnectionInfo(x, y + i, Direction.LEFT, box_index))
        if input[y + i][x + w - 1] == '├':
            result.append(ConnectionInfo(x + w - 1, y + i, Direction.RIGHT, box_index))

    return result

def char_to_directions(c) -> set[Direction] | None:
    match c:
        case '─':
            return {Direction.LEFT, Direction.RIGHT}
        case '│':
            return {Direction.DOWN, Direction.UP}
        case '┌':
            return {Direction.DOWN, Direction.RIGHT}
        case '┐':
            return {Direction.DOWN, Direction.LEFT}
        case '└':
            return {Direction.UP, Direction.RIGHT}
        case '┘':
            return {Direction.UP, Direction.LEFT}
        case '├':
            return {Direction.RIGHT}
        case '┤':
            return {Direction.LEFT}
        case '┬':
            return {Direction.DOWN}
        case '┴':
            return {Direction.UP}
    return None

def direction_to_delta_pos(d: Direction) -> Tuple[int, int]:
    match d:
        case Direction.LEFT:
            return (-1, 0)
        case Direction.RIGHT:
            return (1, 0)
        case Direction.UP:
            return (0, -1)
        case Direction.DOWN:
            return (0, 1)

def invert(d: Direction) -> Direction:
    i = d.value
    return Direction((i + 2) % 4)

def follow_connection(input: list[str], conn: ConnectionInfo) -> ConnectionInfo | None:
    LINES = '─│┌┐└┘├┤┬┴'
    pointer_x = conn.x
    pointer_y = conn.y
    pointer_d = conn.direction
    
    while True:
        dx, dy = direction_to_delta_pos(pointer_d)
        pointer_x += dx
        pointer_y += dy
        c = input[pointer_y][pointer_x]
        
        directions = char_to_directions(c)
        if directions is None:
            return None
        if len(directions) == 1:
            return ConnectionInfo(pointer_x, pointer_y, list(directions)[0], -1)
        
        if invert(pointer_d) not in directions:
            return None
        
        directions.remove(invert(pointer_d))
        pointer_d = list(directions)[0]


def entry(input: str):
    if any(char not in VALID_CHARACTERS for char in input):
        return "nahhh"

    input_as_list: list[str] = input.split('\n')
    boxes: list[BoxInfo] = []

    # Find boxes
    for y, line in enumerate(input_as_list):
        index = -1
        while (index := line.find('┌', index + 1)) != -1:
            box_info = get_box_info(input_as_list, index, y)
            if box_info is None:
                continue
            if box_info == False:
                return "nahhh"
            boxes.append(box_info)

    for i in range(len(boxes)):
        for j in range(len(boxes)):
            if i == j:
                continue
            b1 = boxes[i]
            b2 = boxes[j]

            if b1.x < b2.x and b2.x < b1.x + b1.width and b1.y < b2.y and b2.y < b1.y + b1.height:
                return "nahhh"

    # Find connections
    connections: list[ConnectionInfo] = []
    for i, box in enumerate(boxes):
        connections.extend(find_connections(input_as_list, box, i))
    
    formed_connections = []
    while len(connections) != 0:
        first_connection = connections[0]
        end_connection = follow_connection(input_as_list, first_connection)
        if end_connection is None:
            return "nahhh"
        
        for c in connections:
            if c.x == end_connection.x and c.y == end_connection.y and c.direction == end_connection.direction:
                end_connection.box_index = c.box_index
                break
        if end_connection.box_index == -1:
            return "nahhh"
        
        if end_connection.box_index == connections[0].box_index:
            return "nahhh"

        if (connections[0].box_index, end_connection.box_index) in formed_connections or (end_connection.box_index, connections[0].box_index) in formed_connections:
            return "nahhh"

        formed_connections.append((connections[0].box_index, end_connection.box_index))

        connections.remove(end_connection)
        del connections[0]

    return "legit frfr"

entry #4

written by luatic
submitted at
2 likes

guesses
comments 0

post a comment


.php Unicode text, UTF-8 text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/c/Program\ Files/PHP/php.exe
<?php
ini_set('evil_bit', 1);
$a=[];
while ($b=rtrim(fgets(STDIN), "\n\r"))
	{ $cs=array();
	  preg_match_all('/./u',$b,$cs);
	  $a[]=$cs[0];
	}
function d() {
global $a;
foreach ($a as $r)
{
	foreach ($r as $c)
		echo $c;
	echo "\n";
}
}
function ass($c) {
	if ($c) {
		return;
	}
	echo "invalid!!!";
	exit(69);
}
class RectAngle
{
	public readonly int $x1, $x2, $y1, $y2;
	public function __construct($x1, $x2, $y1, $y2) {
		$this->x1 = $x1;
		$this->x2 = $x2;
		$this->y1 = $y1;
		$this->y2 = $y2;
    }
    public function loop($f) {
		for ($x = $this->x1; $x <= $this->x2; $x++)
			for ($y = $this->y1; $y <= $this->y2; $y++)
				$f($x,$y);
    }
    public function cr() {
    	global $a;
    	$a[$this->y1][$this->x1]=$a[$this->y1][$this->x2]=$a[$this->y2][$this->x1]=$a[$this->y2][$this->x2]=' ';
    }
    public function inp($x,$y) {
    	return $x >= $this->x1 && $x <= $this->x2 && $y >= $this->y1 && $y <= $this->y2;
    }
}
if (!($h=count($a))) {
	exit;
}
$w=count($a[0]);
$rn=0;
$ls=[
	'│' => "UD",
	'─' => "LR",
	'┴' => "LRU",
	'┬' => "LRD",
	'┤' => "LUD",
	'├' => "RUD",
	'┌' => "DR",
	'┐' => "LD",
	'└' => "UR",
	'┘' => "LU",
];
$ds=[
	"L" => [-1,0],
	"R" => [1,0],
	"U" => [0,-1],
	"D" => [0,1],
];
$br=[];
foreach ($a as $y=>$r) {
	foreach ($r as $x=>$c) {
		switch ($c) {
			case '┌':
				$xn = $x;
				while (++$xn < $w && $r[$xn] != '┐');
				if ($xn==$w) continue 2;
				$yn = $y;
				while (++$yn < $h && $a[$yn][$x] != '└');
				if ($yn==$h) continue 2;
				if ($a[$yn][$xn] != '┘') continue 2;
				$re=new RectAngle($x,$xn,$y,$yn);
				$re->cr();
				$con=[++$rn=>true];
				$fl = function($x,$y) use ($re,&$br,$rn,$ds,$ls,$w,$h,&$con) {
					global $a;
					$br[$y][$x] = $rn;
					$in=0;
					$dv=null;
					ass(array_key_exists($a[$y][$x],$ls));
					foreach (str_split($ls[$a[$y][$x]]) as $dc) {
						$dw=$ds[$dc];$xm=$x+$dw[0];$ym=$y+$dw[1];
						if ($re->inp($xm,$ym)) $in++;
						else $dv = $dw;
					}
					ass($in==2);
					$a[$y][$x]=' ';
					if ($dv==null) return;
					$kill=[];
					while (1) {
						$x+=$dv[0];$y+=$dv[1];
						$kill[]=[$x,$y];
						ass((new RectAngle(0,$w-1,0,$h-1))->inp($x,$y));
						$re2 = null;
						if (array_key_exists($y,$br) && array_key_exists($x,$br[$y]))
							$re2 = $br[$y][$x];
						if ($re2!=null) {
							ass(!array_key_exists($re2,$con));
							$con[$re2]=true;
							foreach ($kill as $k)
								$a[$k[1]][$k[0]]=' ';
							break;
						}
						ass(array_key_exists($a[$y][$x],$ls));
						$sl = strlen($ls[$a[$y][$x]]);
						if ($sl==3) break;
						ass($sl==2);
						$dv2=null;
						foreach (str_split($ls[$a[$y][$x]]) as $dc) {
							$dvc=$ds[$dc];
							if ($dvc[0]!=-$dv[0] || $dvc[1]!=-$dv[1])
								$dv2=$dvc; #there is no going back
						}
						$dv=$dv2;
					}
				};
				(new RectAngle($x+1, $xn-1, $y+1, $yn-1))->loop(function($x,$y) {
					 global $a;
					ass($a[$y][$x] == ' ');
				});
				foreach ([
					new RectAngle($x+1, $xn-1, $y, $y),
					new RectAngle($x+1, $xn-1, $yn, $yn),
					new RectAngle($x, $x, $y+1, $yn-1),
					new RectAngle($xn, $xn, $y+1, $yn-1)
				] as $rl) $rl->loop($fl);
				break;
			case '│':
			case '─':
			case '┴':
			case '┬':
			case '┤':
			case '├':
			case '┐':
			case '└':
			case '┘':
			case ' ':
				break; # a ok
			default:
				ass(0);
		}
	}
}
foreach ($a as $r)
	foreach ($r as $c)
		ass($c==' ');
?>

entry #5

written by cdr sa
submitted at
2 likes

guesses
comments 2
cdr sa *known at the time as [author of #5]

Hello. I apologize for my lateness. I was watching cinema. Use the function valid (drawng)', where drawng' refers to an input string.


cdr sa *known at the time as [author of #5]

i hope yall appreciate my code alignment haha, also WOW they hate my smartquotes


post a comment


box_drawng_validity.py Unicode text, UTF-8 text, with CRLF line terminators
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
## Python Version 3.9.7
## There was no `golfing' tomfoolery involved.
## Forsake your place in   clementine  heaven.
## For eso-limes guessed a puzzle   is solved.

def trans (gender):  # Self-explanatory.
    nature = [''] * len (gender [0])
    for facet in gender:
        for f, m in enumerate (facet):
            nature [f] += m
    return  nature

def agree (policy, voters):  # Self-explanatory.
    votes = 0
    for voter in voters:
        votes += policy .count (voter)
    return votes == len (policy)

def fluff (pillow):  # Self-explanatory.
    spine  = [len (thread) for thread in pillow]
    skull  =  max (spine )
    fluffy = [pillow [i] + ' ' * (skull - n)
              for i, n in enumerate (spine)]
    return fluffy

def crush ():  # See docstring for more info.
    """Makes code more concise.

    Args: none

    Returns:
        None

    Side-effects:

        NONE
    """
    return None

def heads (bodies, skulls):  # Self-explanatory.
    cleft, wrung = skulls
    grvyrd = [ ]
    print  = - 1
    for crack, femur in enumerate (bodies):
        if  femur == cleft: print = crack
        if  femur == wrung and  not print == - 1:
            grvyrd +=    [ (print , crack) ]
            print   = - 1
    return  grvyrd

def touch (finger, lovers):  # Self-explanatory.
    tween = lambda adult, child: lambda x: adult < x and x < child
    veins = {taste [0] for taste in lovers}
    atrys = {taste [1] for taste in lovers}
    return ((finger [0] in veins
             and tween (min (atrys), max (atrys)) (finger [1]))
         or (finger [1] in atrys
             and tween (min (veins), max (veins)) (finger [0])))

def spike (drinks, powder, corpus, corpse):  # Don't do this. Don't condone this.
    g,u,r ,d     = powder;
    return [ (i * (1 < e) + [g, r, g, u] [e] [0], i * (e < 2) + [g, r, g, u] [e] [1])
             for e, t in enumerate ([corpus [g [0]] [g [1] : u [1]],
                                     corpus [r [0]] [r [1] : d [1]],
                                     corpse [g [1]] [g [0] : r [0]],
                                     corpse [u [1]] [u [0] : d [0]]])
             for i, crime in enumerate (t) if crime in  drinks [e]]

def trace (legacy, estate, future, killer, towers, memory, crunch):  # Self-explanatory.
    bucket = [3, 4, 1, 2]
    fauna = lambda point, sight: (point [0] + (sight - 2 if sight % 2 else 0),
                                  point [1] + (0 if sight % 2 else sight - 3))
    keith = future [estate [legacy [0]] [legacy [1]]] (fauna)
    flora = fauna  (legacy, keith)
    laura = estate [flora [0]] [flora [1]]
    turns = []
    while laura in future:
        views = future [laura] (bucket [keith - 1])
        if (keith - views) % 2:
            turns .append (flora)
        try:
            keith = views
            flora = fauna (flora, views)
            laura = estate [flora [0]] [flora [1]]
        except IndexError:
            return          False
        if not laura in memory [keith - 1]:
            return          False
        if laura in killer: break
    if not laura in killer: return   False
    if sum (crunch (flora, magic)for magic in towers):
        return     (flora,[legacy] + turns + [flora])
    else:
        return                       False

def clean (skirts, stains): # Self-explanatory
    fresh = skirts
    for speck , stain in enumerate (stains [: - 1]):
        scrub = stain
        xtend = stains [speck + 1]
        g     = xtend [1] - scrub [1]
        flake = g if g else xtend [0] - scrub [0]
        flake = flake // abs (flake)
        while not scrub == xtend:
            s,b = scrub
            scent = fresh [s]
            fresh [s] = scent [: b] + ' ' + scent [b + 1 :]
            scrub = (s + (0 if g else flake),
                     b + (flake if g else 0))
    return fresh

def flesh (packet, scream):  # Self-explanatory
    return '' .join (scream [blood] [bones]
                     for blood in range (packet [0] [0] + 1, packet [- 1] [0])
                     for bones in range (packet [0] [1] + 1, packet [- 1] [1]))

def valid (drawng):  # Whether or not it is a valid box drawing according to the.
    the_following_characters = '─│┌┐└┘├┤┬┴'
    news = print
    tfciatsan = the_following_characters + ' ' + '''
'''
    numb = enumerate
    if not agree (drawng, tfciatsan): return news (
        'inputs always consist exclusively huh well i guess you"re just a liar huh'
    );
    mack = max
    bottom_primary = []
    shet = set
    accordion =      []
    glen = len
    wardrobes =      []
    drawing = drawng .split (tfciatsan [- 1])
    drawing = fluff (drawing)
    widesay = trans (drawing)
    top_candidates          = [                                                ]
    for treat, candy in numb    (         drawing                            ):
        for cadaver in heads    (  candy              , ( '┌' ,         '┐') ):
            top_candidates += [ ( (treat, cadaver [0]), (treat, cadaver [1]) ) ]
    crush                       (                                            )
    for tap, tip in top_candidates:
        wall = drawing [mack (tap [0], tip [0])] [tap [1] + 1 : tip [1]]
        if agree (wall, tfciatsan [: : 9]):
            bottom_primary .append ((tap, tip))
    leftists = [l for l, r in bottom_primary]
    righties = [l for r, l in bottom_primary]
    switch_friends = []
    for mark, carl in numb (leftists):
        car, los = carl
        for benefit in heads (widesay [los], ('┌', '└')):
            if  benefit [0] == car and agree (
                widesay [los] [car + 1 : benefit [1]],
                tfciatsan     [1   :   :          6 ]
    ):
                for bet in heads (widesay [righties [mark] [1]], ('┐', '┘')):
                    berlin  = widesay [righties [mark] [1]]
                    if bet == benefit and agree (berlin    [car + 1 : bet [1]],
                                                 tfciatsan [ 1  :   :      5]):
                        switch_friends += [ (carl,
                                                       righties [mark],
                                             (bet [1],                 los),
                                             (bet [1], righties [mark] [1]))
                        ];
                        break
                break
    boxes = [swinger
             for swinger in switch_friends
             if agree (
                 drawing [swinger [- 1] [0]] [swinger [0] [1] + 1 : swinger [1] [1]],
                 tfciatsan [: : 8]
             )]
    for gawks in boxes:
        if not agree (flesh (gawks, drawing), ' '): return news (
            'but can"t contain each other (or anything that isn"t empty space)'
        );
    furry = spike  # woof woof amirite or am i writ -ing incredible code
    for box, cube in numb (boxes):
        for tuft in furry (tfciatsan [9 : 5 : - 1],
                           cube,
                           drawing,
                           widesay
        ):
            lock =  trace (tuft,
                           drawing,
                           {
                               tfciatsan [0] : lambda x: 6 - x,
                               tfciatsan [1] : lambda x: 4 - x,
                               tfciatsan [2] : lambda x: 7 - x,
                               tfciatsan [3] : lambda x: 5 - x,
                               tfciatsan [4] : lambda x: 5 - x,
                               tfciatsan [5] : lambda x: 3 - x,
                               tfciatsan [6] : lambda x: 4,
                               tfciatsan [7] : lambda x: 2,
                               tfciatsan [8] : lambda x: 3,
                               tfciatsan [9] : lambda x: 1,
                           },
                           tfciatsan [6 : 10],
                           boxes,
                           [
                               tfciatsan [1 : 4] + tfciatsan [6 : 9],
                               tfciatsan [: 9 : 2] + tfciatsan [9],
                               tfciatsan [4 : 8] + tfciatsan [1 : : 8],
                               tfciatsan [: : 8] + tfciatsan [3 : 10 : 2],
                           ],
                           touch,
            );
            if  not   lock:           continue
            if touch (lock [0], cube): return news (
                'the dreaded mushroom'
            );
            accordion .append (lock  [         1            ]     )
            wardrobes .append ((box, [i for i, b in numb (boxes)
                                      if touch (lock [0], b)] [0]))
    for hug in wardrobes:
        if 1 < wardrobes .count (hug): return news (
            'the dreaded anvil'
        );
    disgusting = [[crumb [0], crumb [1], crumb [3], crumb [2], crumb [0]] for crumb in boxes]
    for bug in accordion:
        if not bug[: : - 1] in disgusting: disgusting += [bug]
    for __ in disgusting: drawing = clean (drawing, __)
    return agree (' ' .join (drawing), ' ')

    # you should be able to tell that im not lyricly, at least

entry #6

written by kimapr
submitted at
2 likes

guesses
comments 1
luatic

👍


post a comment


matroska.js.zst Zstandard compressed data (v0.8+), Dictionary ID: None

entry #7

written by olus2000
submitted at
1 like

guesses
comments 2
jan Tusi

The program can be loaded and executed online at https://www.pico-8-edu.com/


luatic

i sure wonder who this could have been made by


post a comment


cg53.p8.png PNG image data, 160 x 205, 8-bit/color RGBA, non-interlaced

entry #8

written by JJRubes
submitted at
0 likes

guesses
comments 0

post a comment


boxes.py Unicode text, UTF-8 text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
class Object:
    def __init__(self, t=None, source=None):
        self.t = t
        self.source = source
        self.connections = []
        self.section = None
        self.left_extent = None
        self.right_extent = None


class CharInfo:
    def __init__(self, char, index):
        self.char = char
        self.index = index
        self.right_obj = None
        self.down_obj = None


def connects_up(character):
    return character in "│└┘├┤┴"


def connects_left(character):
    return character in "─┐┘┤┬┴"


def connects_right(character):
    return character in "─┌└├┬┴"


def connects_down(character):
    return character in "│┌┐├┤┬"


def valid_connections(y, x, drawing):
    above = " " if y == 0 else drawing[y - 1][x]
    below = " " if y == len(drawing) - 1 else drawing[y + 1][x]
    left  = " " if x == 0 else drawing[y][x - 1]
    right = " " if x == len(drawing[y]) - 1 else drawing[y][x + 1]
    curr = drawing[y][x]
    if connects_down(above) != connects_up(curr):
        return False
    if connects_up(below) != connects_down(curr):
        return False
    if connects_right(left) != connects_left(curr):
        return False
    if connects_left(right) != connects_right(curr):
        return False
    return True


def valid_insidedness(curr, aboves):
    if curr.char == " ":
        return True
    for above in aboves:
        if above == None:
            continue
        if above.t == "line":
            continue
        if curr.right_obj == above or curr.down_obj == above:
            continue
        if above.left_extent < curr.index < above.right_extent:
            if above.t == "box":
                return False
            above.t = "line"
    return True


def valid_unification(curr, left, above):
    match curr.char:
        case "┌":
            curr.right_obj = Object()
            curr.right_obj.left_extent = curr.index
            curr.right_obj.section = "top"
            curr.down_obj = curr.right_obj
        case "─":
            curr.right_obj = left
        case "│":
            curr.down_obj = above
        case "┐":
            if left.section == "top":
                left.section = "middle"
                left.right_extent = curr.index
            else:
                if left.t == "box":
                    return False
                left.t = "line"
            curr.down_obj = left
        case "└":
            if curr.index != above.left_extent:
                if above.t == "box":
                    return False
                above.t = "line"
            above.section = "bottom"
            curr.right_obj = above
        case "┘":
            if (above.t == "box" or left.t == "box") and above != left:
                return False
            if above.t == "line" or left.t == "line" or above != left:
                above.t = "line"
                left.t = "line"
                if above == left:
                    return False
                if above in left.connections:
                    return False
                above.connections.append(left)
                left.connections.append(above)
                if above.source == None or left.source == None:
                    if above.source == None:
                        above.source = left.source
                    else:
                        left.source = above.source
                else:
                    if above.source == left.source:
                        return False
                    if above.source in left.source.connections:
                        return False
                    above.source.connections.append(left.source)
                    left.source.connections.append(above.source)
        case "├":
            if above.t == "line":
                return False
            above.t = "box"
            if curr.index == above.left_extent:
                return False
            curr.down_obj = above
            curr.right_obj = Object("line", above)
        case "┬":
            if left.t == "line":
                return False
            left.t = "box"
            if left.section == "top":
                return False
            curr.right_obj = left
            curr.down_obj = Object("line", left)
        case "┤":
            if above.t == "line":
                return False
            above.t = "box"
            if curr.index == above.right_extent:
                return False
            if left.t == "box":
                return False
            left.t = "line"
            if left.source == above:
                return False
            if left.source in above.connections:
                return False
            if left.source == None:
                left.source = above
            else:
                above.connections.append(left.source)
                left.source.connections.append(above)
            curr.down_obj = above
        case "┴":
            if left.t == "line":
                return False
            left.t = "box"
            if left.section == "bottom":
                return False
            if above.t == "box":
                return False
            above.t = "line"
            if above.source == left:
                return False
            if above.source in left.connections:
                return False
            if above.source == None:
                above.source = left
            else:
                left.connections.append(above.source)
                above.source.connections.append(left)
            curr.right_obj = left
        case " ":
            return True
        case _:
            return False
    return True


def valid_box_drawing(drawing):
    if len(drawing) == 0:
        return True
    drawing_width = len(drawing[0])
    left = None
    aboves = []
    for index, character in enumerate(drawing[0]):
        curr = CharInfo(character, index)
        if not valid_connections(0, index, drawing):
            return False
        if not valid_unification(curr, left, None):
            return False
        aboves.append(curr.down_obj)
        left = curr.right_obj
    for line_index, line in enumerate(drawing[1:]):
        if len(line) != drawing_width:
            return False
        left = None
        belows = []
        for index, character in enumerate(line):
            curr = CharInfo(character, index)
            above = aboves[index]
            if not valid_connections(line_index, index, drawing):
                return False
            if not valid_unification(curr, left, above):
                return False
            if not valid_insidedness(curr, aboves):
                return False
            belows.append(curr.down_obj)
            left = curr.right_obj
        aboves = belows
    return True
test.py Unicode text, UTF-8 text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
from boxes import valid_box_drawing

def test(drawing, expected):
    if valid_box_drawing(drawing) == expected:
        print("Passed")
    else:
        print(f"Failed: Expected {expected} for:")
        for line in drawing:
            print(line)


test([], True)
test([""], True)
test([" "], True)
test(["", ""], True)
test([" ", " "], True)
test(
    [
        "┌──────┐",
        "│      │",
        "│      │",
        "│      │",
        "└──────┘"
    ],
    True
)
test(
    [
        "┌──────────────────────────────────────────┐           ",
        "│                                          │           ",
        "│                                          │           ",
        "│                                          │           ",
        "│                                          │           ",
        "│                                          │         ┌┐",
        "│                                          │         └┘",
        "│                                          │           ",
        "│                                          │           ",
        "│                                          │           ",
        "│                                          │           ",
        "│                                          │           ",
        "└──────────────────────────────────────────┘           "
    ],
    True
)
test(
    [
        "┌──────┐┌────┐",
        "│      ││    │",
        "└──────┘└────┘"
    ],
    True
)
test(
    [
        "┌────────┐        ┌────────┐",
        "│        │        │        │",
        "│        ├────────┤        │",
        "│        │        │        │",
        "└────────┘        └────────┘"
    ],
    True
)
test(
    [
        " ┌───────┐ ",
        " │       │ ",
        "┌┴┐     ┌┴┐",
        "└─┘     └─┘"
    ],
    True
)
test(
    [
        " ┌───────┐",
        " │      ┌┘",
        "┌┴┐    ┌┴┐",
        "└─┘    └─┘"
    ],
    True
)
test(
    [
        "┌────────┐ ",
        "│ ┌─┐    │ ",
        "│ └┬┘    │ ",
        "└──┘     │ ",
        "        ┌┴┐",
        "        └─┘"
    ],
    True
)
test(
    [
        "┌─┐",
        "└┬┘",
        "┌┴┐",
        "└─┘"
    ],
    True
)
test(
    [
        "┌┐┌┐",
        "│├┤│",
        "└┘└┘"
    ],
    True
)
test(
    [
        "┌─┐┌─┐",
        "│ ├┤ │",
        "└┬┘└┬┘",
        "┌┴┐┌┴┐",
        "│ ├┤ │",
        "└─┘└─┘"
    ],
    True
)
test(
    [
        "        ┌───────┐",
        "        │       │",
        "  ┌─────┤       │",
        "  │     └───────┘",
        "┌─┴──┐           ",
        "│    │           ",
        "│    │           ",
        "└────┘           "
    ],
    True
)
test(
    [
        "┌──────┐             ",
        "└┬──┬──┘    ┌───────┐",
        " │  │       │       │",
        " │  └───────┤       │",
        " └────┐     └───┬───┘",
        "    ┌─┴──┐     ┌┘    ",
        "    │    │    ┌┘     ",
        "    │    ├┐   └────┐ ",
        "    └────┘└────────┘ "
    ],
    True
)
test(
    [
        "┌──────┐    ",
        "│      │    ",
        "│      └───┐",
        "│          │",
        "└──────────┘"
    ],
    False
)
test(
    [
        "a",
    ],
    False
)
test(
    [
        "┌",
    ],
    False
)
test(
    [
        "┌──────┬────┐",
        "│      │    │",
        "└──────┴────┘"
    ],
    False
)
test(
    [
        "     ┌────┐",
        "┌────┼────┘",
        "└────┘     "
    ],
    False
)
test(
    [
        "┌──────────────────────────────────────────┐",
        "│                                          │",
        "│                                          │",
        "│       ┌┐        ┌┐     ┌───────┐         │",
        "│       ││┌┐      ││     │┌─────┐│         │",
        "│       ││└┘┌┐    ││     ││     ││         │",
        "│       ││  └┘┌┐  ││     ││     ││         │",
        "│       ││    └┘┌┐││     ││     ││         │",
        "│       ││      └┘││     ││     ││         │",
        "│       ││        ││     │└─────┘│         │",
        "│       └┘        └┘     └───────┘         │",
        "│                                          │",
        "└──────────────────────────────────────────┘"
    ],
    False
)
test(
    [
        "┌──────┐          ┌───────",
        "│      │          │      │",
        "│                 │      │",
        "└──────┘          └──────┘",
        "                          ",
        "         ┌──────┐         ",
        "         │      │         ",
        "         │      ┤         ",
        "         └──────┘         "
    ],
    False
)
test(
    [
        "┌──────┐",
        "│      │",
        "│       ",
        "└──────┘"
    ],
    False
)
test(
    [
        "          ",
        " ┌─────── ",
        " │      │ ",
        " │      │ ",
        " └──────┘ ",
        "          "
    ],
    False
)
test(
    [
        "┌──────┐",
        "│      │",
        "│      ┤",
        "└──────┘"
    ],
    False
)
test(
    [
        "    ┌──────────────────┐    ",
        "┌───┴────┐        ┌────┴───┐",
        "│        │        │        │",
        "│        ├────────┤        │",
        "│        │        │        │",
        "└────────┘        └────────┘"
    ],
    False
)
test(
    [
        "┌────────┐        ┌────────┐",
        "│        │        │        │",
        "│        ├────────┤        │",
        "│        │        │        │",
        "└────────┤        └────────┘",
        "         │                  ",
        "         ├────────┐         ",
        "         │        │         ",
        "         │        │         ",
        "         │        │         ",
        "         └────────┘         "
    ],
    False
)
test(
    [
        "┌────────┐        ┌────────┐",
        "│        │        │        │",
        "│        ├────────┤        │",
        "│        │        │        │",
        "└────────┤        ├────────┘",
        "         │        │         ",
        "         ├────────┤         ",
        "         │        │         ",
        "         │        │         ",
        "         │        │         ",
        "         └────────┘         "
    ],
    False
)
test(
    [
        "┌┐     ┌┐     ┌┐     ┌┐  ",
        "││     ││     ││     ││  ",
        "│├──┴──┤│     │├──┐  │├─┐",
        "││     ││     ││  │  ││ │",
        "└┘     └┘     └┘  │  └┘ │",
        "                  │     │",
        "┌┐     ┌┐     ┌┐  │  ┌┐ │",
        "││     ││     ││  │  ││ │",
        "│├─────││     │├──┼──┤│ │",
        "││     ││     ││  │  ││ │",
        "└┘     └┘     └┘  │  └┘ │",
        "                  └─────┘"
    ],
    False
)
test(
    [
        "┌┐     ┌┐",
        "││     ││",
        "│├──┴──┤│",
        "││     ││",
        "└┘     └┘"
    ],
    False
)
test(
    [
        "┌┐     ┌┐",
        "││     ││",
        "│├─────││",
        "││     ││",
        "└┘     └┘"
    ],
    False
)
test(
    [
        "┌┐     ┌┐  ",
        "││     ││  ",
        "│├──┐  │├─┐",
        "││  │  ││ │",
        "└┘  │  └┘ │",
        "    │     │",
        "┌┐  │  ┌┐ │",
        "││  │  ││ │",
        "│├──┼──┤│ │",
        "││  │  ││ │",
        "└┘  │  └┘ │",
        "    └─────┘"
    ],
    False
)
test(
    [
        "┌────────┐",
        "│        │",
        "│        │",
        "│       ┌┘",
        "└───────┘ "
    ],
    False
)