41
\$\begingroup\$

Challenge

You will be given a table as input, drawn with ASCII | and _. Your task is to set the chairs around it.

Example

Input:

 ____
|    |
|    |
|    |
|    |
|____|

Output:

 _^_^_
<     >
|     |
<     >
|     |
<_ _ _>
  v v

Those chairs are made of <> and v^.

Another example:

The line must have as many chairs as possible in it.

  _____
 |     |_____
 |           |
 |           |
 |           |
 |      _____|
 |_____|


  _^_^_
 <     |_^_^_
 |           >
 <           |
 |           |
 <      _ _ _>
 |_ _ _| v v
   v v

There must be spaces between every chair. And >_^_^_< is invalid, it should be |_^_^_|.

  _____       _____
 |     |_____|     |
 |                 |
 |                 |
 |                 |
 |      ___________|
 |_____|


  _^_^_       _^_^_
 <     |_^_^_|     >
 |                 |
 <                 >
 |                 |
 <      _ _ _ _ _ _>
 |_ _ _| v v v v v
   v v

No chairs may be on the inside of a "donut".

  _________________
 |      _____      |
 |     |     |     |
 |     |     |     |
 |     |_____|     |
 |_________________|


  _^_^_^_^_^_^_^_^_
 <      _____      >
 |     |     |     |
 <     |     |     >
 |     |_____|     |
 <_ _ _ _ _ _ _ _ _>
   v v v v v v v v

^ and v prioritise < and >. No chair on it's own (it has to have at least one | or _ in the row).

  _________________
 |      _____      |
 |     |     |     |
 |     |     |_____|
 |     |_____
 |___________|


  _^_^_^_^_^_^_^_^_
 <      _ _ _      >
 |     | v v |     |
 <     >     <_ _ _>
 |     |_^_^_  v v
 <_ _ _ _ _ _|
   v v v v v

This is code golf, so shortest code wins.

\$\endgroup\$
11
  • 2
    \$\begingroup\$ I am confused, why are the chairs embedded into the table from sides ? \$\endgroup\$
    – Optimizer
    May 19, 2015 at 15:00
  • \$\begingroup\$ If I recall correctly, your original sandbox post had a space between the vertical table line and the chair line. Just like there is a little space between the horizontal table lines and the chairs. \$\endgroup\$
    – Optimizer
    May 19, 2015 at 15:02
  • 1
    \$\begingroup\$ it looks like that chairs are placed with 1 distance with each other , but any input's surrounding is not dividable by 2 . how the program should start puting chairs . clockwise or anti-clock wise ? from top right corner , top left corner etc ? \$\endgroup\$
    – user55673
    Jun 24, 2016 at 16:38
  • 1
    \$\begingroup\$ also i think there is a problem in third sample - there is an extra space between second and third "top" chairs - and also in last example , bottom-right corner \$\endgroup\$
    – user55673
    Jun 24, 2016 at 16:38
  • 1
    \$\begingroup\$ The first test case seems to be broken. The input is only 4 wide and the output is 5. \$\endgroup\$
    – Wheat Wizard
    Nov 21, 2016 at 4:46

1 Answer 1

33
+50
\$\begingroup\$

Python 2, 1033 1007 924 879 829 787 713 699 692 691 688 687 672 670 664 659 654 648 643 642 630 625 623 620 570 560 554 545 518 514 513 510 505 492 476 454 451 443 bytes

6 bytes saved thanks to Riley

6 bytes saved thanks to Adnan

Since this question is over a year old and still has no answers I thought I'd give it a try.

n,i,o,u="\nI _";R=lambda x:range(1,x-1)
b=open(i).read()
s=b.split(n)
z=max(map(len,s))+3
a=[list(i+x.ljust(z,i))for x in[i]+s+[i]]
for x in R(len(a))*len(b):
 A=a[x];B=a[x+1];C=a[x-1]
 for y in R(z):
    D=A[y-1:y+2];k=B[y];j=A[y+1]
    if(i in[C[y],k]+D+(k==u)*B[y-1:y+2]or"V"==j)&(A[y]==o):A[y]=i
    if"|"==A[y]==C[y]:A[y]={i:"|",j:">",A[y-1]:"<"}[i]
    if[u]*3==D:A[y],B[y]={i:u+k,C[y]:"^"+k,k:" V"}[i]
print n.join(`y`[2::5]for y in a).replace(i,o)

Try it online!

The program reads the table a file named I and prints the table with its chairs to std::out. I was not sure about a bunch of the edge cases so I took my best judgement (whatever took the least effort) but it seems to pass all the test cases. Some of the outputs don't match exactly but they all have the same number of chairs.

Explanation

The first line pretty simply sets up some definitions that will save us bytes in the future:

(I will unpack these macros for readability in future lines)

n,i,o="\nI ";R=lambda x:range(1,x-1)

Then we will open a file named I because we already have a variable that is short for that so it saves a few bytes.

b=open("I").read().split("\n")

We split along newlines to create a list of strings (The rows of the image)

s=b.split(n)

I then find the length of the longest line so that I can pad all lines to that length. (I also add 3 because we need a bit of additional padding)

 z=max(map(len,s))+3

Then we perform the actual padding and create a border of I characters around the edge. This is because we will need to tell the difference between the inside and the outside of the shape later on. We will also change the data type from a list of strings to a list of list of characters (length 1 strings).

a=[list("I"+x.ljust(z,"I"))for x in["I"]+s+["I"]]

The next line is just another byte saving definition.

(I will also unpack this one)

B=R(len(a))

Now we want to spread I characters to everywhere outside of the shape. We can do this with a pseudo-cellular automaton. Each I will spread to any adjacent characters. We could loop until the automaton stabilizes however this cannot take more iterations than there are characters so we just loop through every character in b (the original input)

for _ in b:

For each iteration we want to pass over every character in the 2D list (excluding the outermost padding)

 for x in range(1,len(a)-1):
    A=a[x]  #<--Another definition I will fill in for clarity
    for y in range(1,z-1):

For each position we run the following code:

if("I" in[a[x+1][y],a[x-1][y]]+a[x][y-1:y+2])&(a[x][y]==" "):a[x][y]=" "

Lets break this down.

We have an if with two conditions separated by a & (bitwise and)

The first one simply checks if there is an I in any of the adjacent cells and the second one just checks if the current cell is a " ". If we pass those conditions we set the current cell to be an I.


Now that we have determined the outside and inside of the shape we can start to place the chairs around the table.

Once again we loop through all of the cells (and set some more shorthands)

for x in range(1,len(a)-1):
 A=a[x]
 for y in range(1,z-1):
        k=a[x+1][y]
 

Now here's my favorite part. If you have trudged through my boring, mostly definition based, golfing so far I am going to reward you with a nice tidbit of clever golfing (if I do say so myself).

A little background in python:

In Python if you attempt to assign an dictionary key twice it asigns the latter one. For example

>>> {1:"a",1:"b"}[1]
'b'

We will abuse this property to assign the current cell to a particular character.

The first condition is

if["_"]*3==a[x][y-1:y+2]:a[x][y],a[x+1][y]={"I":"_"+a[x+1][y],a[x-1][y]:"^ ",a[x+1][y]:" V"}["I"]

If the cell is in the middle of an edge of 3 _ characters we will reassign the current cell and the cell below it. We will assign it to the result of indexing an overloaded dictionary by I. We first set our default with the pair "I":"_"+a[x+1][y] this means if there is no change we will assign the two cells back to their original values. Next we add the pair a[x-1][y]:"^ ". This wont do anything (important) unless the cell above the current one (a[x-1][y]) is filled with an I. If it has an I in it it will override the default telling us to place a chair at the current cell. Next we move on to the cell below the current cell if that cell is I we again override to place an upwards facing chair below the current spot.

The next condition is a tad simpler

if"|"==a[x][y]==a[x-1][y]:a[x][y]={"I":"|",A[y+1]:">",A[y-1]:"<"}["I"]   

We check if the current cell and the cell above it are both |. If so we set up a dictionary.

The first pair in the dictionary "I":"|" sets the default. Since we are going to access the key I if I does not get reassigned it will default back to | (the character it already is) and do nothing.

We the add the two keys A[y+1]:">",A[y-1]:"<" If either of the two cells to the left and right are I then it will reassign the current cell to a chair pointing in the direction of the outside.


Now we just have to output. However we can't just print, there are a couple of housekeeping things we have to do first. We have to convert back to a string and remove all of the Is we created. This is done in one line.

print "\n".join(`y`[2::5]for y in a).replace("I"," ")
\$\endgroup\$
10
  • \$\begingroup\$ Can't you use a space for the first level of indent, tab for two, a tab and a space for three? That'll save a few bytes. \$\endgroup\$
    – Riley
    Oct 18, 2016 at 17:52
  • 3
    \$\begingroup\$ This may be the most re-golfed answer. \$\endgroup\$ Nov 23, 2016 at 17:00
  • 2
    \$\begingroup\$ Does i,o="I " instead of i="I";o=" " work? \$\endgroup\$
    – Adnan
    Nov 26, 2016 at 23:40
  • 1
    \$\begingroup\$ @ErikGolferエリックゴルファー Making n costs 4 bytes and saves me 6. Although I don't use it often it does save 2 bytes. \$\endgroup\$
    – Wheat Wizard
    Dec 11, 2016 at 17:27
  • 1
    \$\begingroup\$ @Pietu1998 Thanks for pointing that out. I fixed the problem \$\endgroup\$
    – Wheat Wizard
    Jan 18, 2017 at 14:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.