42
\$\begingroup\$

Here is a diagram of a prison using ASCII characters:

+------------------------------+
|                              |
|   X               X          |
|                              |
|                              D
D                              |
|                              |
|                              |
|        X           X   X     |
|                              |
+------------------------------+

Walls are made out of pipe characters |, dashes -, and pillars + for corners and intersections. There are also two doors marked with D (which will always be on the left and right walls). The prison is filled with scary people marked with X.

The goal is to build walls to satisfy the following:

  1. Each person is in solitary confinement;
  2. There is a corridor running between the two doors;
  3. Each cell contains exactly one door, which is directly connected to the main corridor;
  4. All space in the prison is used by the cells and the corridor;
  5. Each cell contains a person (that is, there are no empty cells).

The corridor is a single path, doesn't branch off, and is always one character wide. Here's a solution for the prison above:

+---------+--------------------+
|         |                    |
|   X     |         X          |
|         |           +--------+
+------D--+-----D-----+        D
D                       +---D--+
+----D--------+---D-----+      |
|             |         |      |
|        X    |      X  |X     |
|             |         |      |
+-------------+---------+------+

You can assume that any input prison will always have a valid output. Here are some more input prisons, along with possible outputs:

+------------------------------+
|X X X X X X X X X X X X X X X |
|                              |
D                              D
|                              |
|              X               |
+------------------------------+

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
|X|X|X|X|X|X|X|X|X|X|X|X|X|X|X |
+D+D+D+D+D+D+D+D+D+D+D+D+D+D+D-+
D                              D
+----------------------D-------+
|              X               |
+------------------------------+

+-----------+
|X          |
|           |
|           |
|X         X|
|           |
|          X|
|           |
D           D
+-----------+

+-+-------+-+
|X|       D |
| D +---+ | |
+-+ |     | |
|X| | +---+X|
| | | |   +-+
| D | |    X|
+-+ | +-D---+
D   |       D
+---+-------+

+----------------+
|X    X    X    X|
|                |
D                |
|                |
|X    X    X     |
|                |
|                |
|                |
|     X    X     D
|                |
|                |
+----------------+

+---+---+----+---+
|X  | X |  X |  X|
+--D+--D+---D+--D+
D                |
+---+---+------+ |
|X  | X |  X   | |
+--D+--D+---D--+ |
|                |
| +-----+------+-+
| |   X |  X   | D
| +----D+---D--+ |
|                |
+----------------+
\$\endgroup\$
  • 4
    \$\begingroup\$ Possible solution: pathway first rooms next \$\endgroup\$ – Matthew Roh Mar 13 '17 at 22:59
  • \$\begingroup\$ Related, might be helpful when constructing the walls. \$\endgroup\$ – TheLethalCoder Aug 2 '17 at 11:46
  • 1
    \$\begingroup\$ What is preventing me to put walls and a door directly around each prisoner (like in your second example) and declare the rest of the space as a corridor? \$\endgroup\$ – Fels Aug 2 '17 at 14:28
  • \$\begingroup\$ Sorry, found it: "one character wide". \$\endgroup\$ – Fels Aug 2 '17 at 14:35
  • 1
    \$\begingroup\$ This may help. \$\endgroup\$ – TehPers Aug 2 '17 at 15:21
15
+100
\$\begingroup\$

Python 2, 2986 2881 2949 2135 2075 2071 1996 bytes

  • Saved 105 bytes, implemented the program as a function to comply with standard rules. Implemented Wheat Wizard's tab and space suggestion.
  • Added 68 bytes due to fixing a bug.
  • Saved 814+51 bytes thanks to Halvard Hummel.
  • Saved 9+4 bytes.
  • Saved 4 bytes thanks to Erik the Outgolfer.
  • Saved 71 bytes thanks to ppperry's suggestion.
exec r"""def Z(P):
 H,n,I,o,O,i,d,D,W=[type,range]+list(" dD#xX*");R=(1,0),(-1,0),(0,1),(0,-1)
 def F(j,k,l):P[j][k]=l
 def E(j,k,v,w):
	if G(j,k,v):F(k,j,w)
 def q(b,c,d):[[E(j+J,k+K,b,c)for J,K in M]&L if G(j,k,d)]
 def A(e,r,l,o,q):
	S,E,P[q][o],Q,X=P[q][o],e,0,[(o,q)],0
	for a,b in Q:
	 &R:
		x,y=a+j,b+k
		if(0<=x<w!=0<=y<h)<1:continue
		if e in((x,y),P[y][x]):X=1;e=x,y;break
		if I!=P[y][x]:continue
		F(y,x,P[b][a]+1);Q+=[(x,y)]
	 if X:break
	p,i=e,0
	while(o,q)!=p:
	 a,b=p;P[b][a],m=[r,l][l and i==1],0
	 &R:
		x,y=a+j,b+k
		if(0<=x<w!=0<=y<h)-1:continue
		if(H(P[y][x])==H(0))*(m==0 or P[y][x]<P[m[1]][m[0]]):m=x,y
	 p=m;i+=1
	P[q][o],P[e[1]][e[0]]=S,E;[F(k,j,I)&L if H(P[k][j])==H(0)]
 def B(N):
	[[E(j,k,"x*",I),0<j<w-1 and E(j,k,O,I)]&L]
	&L:
	 if G(j,k,D):[E(j+J,k+K,I,d)for J,K in M]
	 if G(j,k,O)and j==0:T=0,k
	if N:A(O,o,0,*T)
	U,V=M[-1];[[[F(k+K,j+J,I)for J,K in M if(P[k+K][j+J]!=i)*((0<=j+J+U<w!=0<=k+K+V<h and G(j+J+U,k+K+V,D))<1)],F(k,j,W),A(o,W,O,j,k),q(I,d,W),F(k,j,D)]&L if G(j,k,D)];q("xX*# @+-|",i,o)
 for j in"|+-":P=P.replace(j,i)
 P=list(map(list,P.split("\n")));h=len(P);w=len(P[0]);b,L,M,G="#+-|D",[(k,j)for k in n(w)for j in n(h)],[(k-1,j-1)for k in n(3)for j in n(3)if(j,k)!=(1,1)],lambda j,k,v:P[k][j]in v
 B(1);Y=lambda:0<j<w-1!=0<k<h-1and G(j,k,i);[[[F(k,j,o),F(k+g,j+N,i)]for N,g in((-1,-1),(-1,1),(1,-1),(1,1))if P[k][j+g]+P[k][j-g]==P[k+N][j+g]+P[k-N][j]==P[k+N][j]+i==o+i]&L if(j in(1,w-2)or k in(1,h-2))*Y()for N in n(w*h)];[F(k,j,I)&L if Y()];B(0)
 def c(x,y,b,l,d,f,Q):
	F(y,x,b)
	for J,K in M:Q+=[[],[(x+J,y+K)]][G(x+J,y+K,l)];E(x+J,y+K,d,f)
 &L:
	if G(j,k,D):Q=[(j,k)];[c(x,y,"@",W,d,I,Q)for x,y in Q if G(x,y,"X*")];[G(u,v,"X*")and[E(u+U,v+V,I,d)for U,V in M]or E(u,v,"@",I)for u,v in L];Q=Q[:1];[c(x,y,"$",I,"x*",i,Q)for x,y in Q];F(k,j,D)
 &L:E(j,k,"@$d",I);X=(k>0and G(j,k-1,b))+(k<h-1and G(j,k+1,b))-(j>0and G(j-1,k,b))-(j<w-1and G(j+1,k,b));E(j,k,i,{2:"+",X:"|",-X:"-"}[2])
 print"\n".join("".join(p)for p in P)""".replace("&","for j,k in ")

Try it online!

It was golfed down significantly; yet there may still be room for improvement. This piece of code, however, solves all test cases. Does not run very efficiently; for large prisons the architect may take their time to figure it out.
Uses a simple pathfinding algorithm to connect both doors and the prisoners to the corridor. Then it encapsulates all prisoners and their walls and pushes said walls in empty space until all of it is filled. As a final step, the ASCII art appearance is implemented.

Took me for sure several hours to write. I hope it also works on other prisons than the test cases. (You cannot test them all, can you?)

\$\endgroup\$
  • \$\begingroup\$ For multiple levels of indentation you can alternate spaces and tabs. (space = 1 indent, tab = 2 indents) \$\endgroup\$ – Wheat Wizard Aug 6 '17 at 4:26
  • 1
    \$\begingroup\$ Also this is a snippet. Meaning you take input from a pre-initialized variable (P). This is not an allowed IO format. You should use either input() or define a function. \$\endgroup\$ – Wheat Wizard Aug 6 '17 at 4:35
  • \$\begingroup\$ Being that this is such a large piece of code, there are also about a hundred smaller things I see that can be golfed. I'm not going to list them all now. But if you would like me to help you go through them you can ping me in chat. Since you are a relatively new user I don't know how familiar with python golfing you are. Perhaps your still working on golfing this by yourself. :) \$\endgroup\$ – Wheat Wizard Aug 6 '17 at 4:48
  • \$\begingroup\$ Here is a way shorter version that implements a few of the tricks I saw. It's by no means the furthest it can be golfed down, I don't even know your algorithm. But its about 300 bytes shorter. It is still a snippet though, so you will need to make it comply. \$\endgroup\$ – Wheat Wizard Aug 6 '17 at 6:31
  • 1
    \$\begingroup\$ @HalvardHummel The goal is reached; we are under 2000 bytes! \$\endgroup\$ – Jonathan Frech Aug 11 '17 at 0:12
4
\$\begingroup\$

C, 3732 3642 bytes

I could definitely golf this a bit further, but it is a pretty nice start. I did not initially know that my approach had a name so shout out to @TehPers for giving me a name to research. I definitely enjoyed the challenge that this question offered. :)

-63 bytes from @Jonathan's suggestions. I also replaced char with typedef char R and replaced all character literals that are smaller than 100 with their ASCII values for a total of 90 bytes

A quick explanation of my code.

  1. Convert char array to an ideal integer array (0 is space, 1 is wall, etc.)
  2. Generate the Voronoi diagram using the people as the points
  3. Use the intersections (a 5 surrounded by at least three other 5s) as pivot points for the path
  4. Create the corridor using a directionally biased path finding algorithm (if it's going one way, favor paths that do not change direction). It also modifies the grid so that it favors traveling next to an already made corridor.
  5. Regenerate diagram to place final walls. Ensures that all space is used.
  6. Convert map back to a properly formatted ASCII representation and print.

To use this program, pass the map as either a string with newline characters or with each level seperated by a space as in the following example.

program-name.exe "+-----------+ |X          | |           | |           | |X         X| |           | |          X| |           | D           D +-----------+ "

+------+----+
|X     |    |
|    +D+-+  |
+----+   |  |
|X   | + D X|
|    | | +--+
|    | | | X|
+D---+ | +-D+
D      |    D
+------+----+

code

typedef int Q;typedef char R;typedef struct{Q x,y,v;}P;w,h,A,Y,Z,x,y,i,j,e,f,m,n,v;P*t,*u,*s;I(R*a,Q x,Q y,R c){a[x+y*w]=c;}G(Q*a,Q x,Q y){if(x>-1&&x<w&&y>-1&&y<h)return a[x+y*w];return-1;}J(Q*a,Q x,Q y,Q c){a[x+y*w]=c;}P*E(Q n,Q*a,Q*c){P*r=0;for(i=v=0;i<A;i++)if(a[i]==n)r=(P*)realloc(r,sizeof(P)*(v+1)),r[v].x=i%w,r[v].y=i/w,r[v].v=v,*c=++v;return r;}C(Q*a,Q x,Q y,Q b){return(G(a,x-1,y)==b)+(G(a,x+1,y)==b)+(G(a,x,y-1)==b)+(G(a,x,y+1)==b);}H(Q*a,Q b){P q[A],r[A];m=Y,n=0;for(i=0;i<Y;i++)q[i]=t[i];while(m){while(m){x=q[m-1].x,y=q[m-1].y,v=q[m-1].v;i=G(a,x,y);if(i!=b&&i!=1){for(f=-1;f<2;f++){for(e=-1;e<2;e++){i=G(a,x+e,y+f);if(i==0){J(a,x+e,y+f,v+8);r[n].x=x+e;r[n].y=y+f;r[n].v=v;n++;}else if(i>=8&&i!=v+8)J(a,x+e,y+f,b);}}}m--;}for(i=0;i<n;i++)q[i]=r[i];m=n;n=0;}}B(P p,Q*a,Q*b){for(i=m=n=0;i<A;i++)if(b[i]>-2)b[i]=-1;P q[A],r[A];q[0]=p,q[0].v=0,b[p.x+p.y*w]=0;while(m+1){while(m+1){x=q[m].x,y=q[m].y,v=q[m].v;for(f=-1;f<2;f++){for(e=-1;e<2;e++){if(e!=0&&f!=0||(x+e<0||x+e>=w||y+f<0||y+f>=h))continue;i=G(a,x+e,y+f);if(i!=7&&i!=1&&i!=0){j=3;if(i==4||i==5)j=1;if(x+e!=p.x&&y+f!=p.y)j++;Q*p=&b[x+e+(y+f)*w];if(*p!=-2&&(*p==-1||*p>v+j)){*p=v+j;if(i!=2)r[n].x=x+e,r[n].y=y+f,r[n].v=v+j,n++;}}}}m--;}for(i=0;i<n;i++){q[i]=r[i];}m=n-1,n=0;}}D(P S,P*T,Q n,P U,Q*a){Q m[A];Q x,y,v=0,c=0,d=1,d1=1;for(i=0;i<n;i++)T[i].v=0;for(i=0;i<A;i++)m[i]=-1;x=S.x,y=S.y;if(n==0){B(U,a,m);goto fin;}while(v<n){j=-1;for(i=0;i<n;i++)if(T[i].v==0)if(j==-1||abs(T[i].x-x)+abs(T[i].y-y)-(T[i].x==x)*!d*2-(T[i].y==y)*d*2<abs(T[j].x-x)+abs(T[j].y-y)-(T[j].x==x)*!d*2-(T[j].y==y)*d*2)j=i;T[j].v=1;B(T[j],a,m);fin:v++;c=m[x+y*w];while(c>0||c==-1){Q tx,ty;j=-1;for(f=-1;f<2;f++){for(e=-1;e<2;e++){if(e!=0&&f!=0)continue;if(x+e<0||x+e>=w||y+f<0||y+f>=h)continue;i=G(m,x+e,y+f);if(i>-1&&(i<c||c==-1)){if(j==-1||j>i||((e*d||f*!d)&&j==i)){j=i;tx=x+e,ty=y+f;d1=e!=0;}}}}J(m,x-1*!d1,y-1*d1,-2);J(m,x+1*!d1,y+1*d1,-2);d=d1;x=tx,y=ty,c=j;if(G(a,x,y)!=2)J(a,x,y,0);}for(f=0;f<h;f++)for(e=0;e<w;e++)if((i=G(a,e,f))>3&&i!=7)if(C(m,e,f,-2))J(a,e,f,5);if(v==n){B(U,a,m);goto fin;}}}main(Q c,R**v){R*a=v[1];w=strchr(a,'|')-a;h=(strchr(a+w,43)-a)/w+1;A=w*h;Q p[A];for(y=0;y<h;y++)for(x=0;x<w;x++){c=a[x+y*w];J(p,x,y,0);if(c==45||c=='|'||c==43)J(p,x,y,1);if(c==68)J(p,x,y,2);if(c==88)J(p,x,y,3);}t=E(3,p,&Y);u=E(2,p,&Z);H(p,5);for(c=0;c<Y;c++)for(y=-1;y<2;y++)for(x=-1;x<2;x++)if(G(p,t[c].x+x,t[c].y+y)>=4)J(p,x+t[c].x,y+t[c].y,7);for(y=1;y<h-1;y++)for(x=1;x<w-2;x++)if(G(p,x,y)==5)if(C(p,x,y,5)>2)J(p,x,y,4);s=E(4,p,&c);for(i=0;i<c;i++)s[i].v=0;for(y=1;y<h-1;y++)for(x=1;x<w-2;x++)if(G(p,x,y)>=8)if(C(p,x,y,5))J(p,x,y,4);i=u[0].x!=0;D(u[i],s,c,u[!i],p);for(y=0;y<h;y++){for(x=0;x<w;x++){i=0;if(G(p,x,y)>2){for(f=-1;f<2;f++)for(e=-1;e<2;e++)i+=G(p,x+e,y+f)==0;if(i>0)J(p,x,y,6);}}}free(s);for(i=0;i<A;i++)if(p[i]>=7||p[i]==4||p[i]==5)p[i]=0;for(y=0;y<h;y++){for(x=0;x<w-1;x++){if((x==0||x==w-2||y==0||y==h-1)&&G(p,x,y)!=2)J(p,x,y,1);}}H(p,1);P q[A],r[A];for(i=0;i<Y;i++){m=1,n=0;q[0]=t[i];while(m){while(m){x=q[m-1].x,y=q[m-1].y;for(f=-1;f<2;f++){for(e=-1;e<2;e++){if(e!=0&&f!=0)continue;c=G(p,x+e,y+f);if(c==6){if(G(p,x+e*2,y+f*2)==0){J(p,x+e,y+f,2);m=1,n=0;e=f=2;}}else if(c!=1&&c!=3&&c!=7){J(p,x+e,y+f,7);r[n].x=x+e;r[n].y=y+f;n++;}}}m--;}for(c=0;c<n;c++)q[c]=r[c];m=n;n=0;}}for(i=0;i<A;i++)if(p[i]==6)p[i]=1;R b[A];for(y=0;y<h;y++){for(x=0;x<w;x++){c=G(p,x,y);I(b,x,y,32);if(c==1){i=0;if(G(p,x,y-1)==1||G(p,x,y-1)==2)i|=1;if(G(p,x,y+1)==1||G(p,x,y+1)==2)i|=2;if(G(p,x-1,y)==1||G(p,x-1,y)==2)i|=4;if(G(p,x+1,y)==1||G(p,x+1,y)==2)i|=8;if(i==3)I(b,x,y,'|');else if(i==12)I(b,x,y,45);else I(b,x,y,43);}if(c==2)I(b,x,y,68);if(c==3)I(b,x,y,88);if(x==w-1)I(b,x,y,10);}}b[A-1]=0;puts(b);}
\$\endgroup\$
  • \$\begingroup\$ I know that it is good practice in C to free memory when you are done with it, yet when golfing it takes unnecessary bytes. You could save 16 bytes by simply removing free(t);free(u); at the end of your program. Also, '\0' is equal to 0, saving another 3 bytes. \$\endgroup\$ – Jonathan Frech Aug 14 '17 at 3:57
  • \$\begingroup\$ If you add something like typedef int Q; and replace all occurrences of int with Q, you could save another 44 bytes. \$\endgroup\$ – Jonathan Frech Aug 14 '17 at 4:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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