Prison Architect, ASCII version

42

9

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--+ |
|                |
+----------------+

absinthe

Posted 2017-03-13T21:49:22.347

Reputation: 8 359

4Possible solution: pathway first rooms next – Matthew Roh – 2017-03-13T22:59:30.707

Related, might be helpful when constructing the walls. – TheLethalCoder – 2017-08-02T11:46:53.413

1What 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? – Fels – 2017-08-02T14:28:10.220

Sorry, found it: "one character wide". – Fels – 2017-08-02T14:35:08.770

1This may help. – TehPers – 2017-08-02T15:21:29.033

Answers

15

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?)

Jonathan Frech

Posted 2017-03-13T21:49:22.347

Reputation: 6 681

For multiple levels of indentation you can alternate spaces and tabs. (space = 1 indent, tab = 2 indents) – Post Rock Garf Hunter – 2017-08-06T04:26:40.957

1Also 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. – Post Rock Garf Hunter – 2017-08-06T04:35:32.553

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. :) – Post Rock Garf Hunter – 2017-08-06T04:48:47.127

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. – Post Rock Garf Hunter – 2017-08-06T06:31:06.777

90 bytes shorter, might've missed some too. – Erik the Outgolfer – 2017-08-06T09:17:05.733

2262 bytes – Halvard Hummel – 2017-08-06T13:25:13.977

2135 bytes – Halvard Hummel – 2017-08-06T18:30:59.450

Thanks to Wheat Wizard, Erik the Outgolfer and Halvard Hummel for golfing suggestions; I now implemented Halvard Hummel's golfed solution as it currently is the shortest. – Jonathan Frech – 2017-08-06T19:35:44.887

2084 bytes Should be possible to golf this to under 2000 bytes – Halvard Hummel – 2017-08-07T16:27:32.967

2075 bytes Golfed the second line. – Jonathan Frech – 2017-08-07T18:43:57.013

You can save a few more bytes by wrapping the code in an exec statement and .replaceing a single character with for j,k in. That code sequence has length 10, and is used 11 times, well within the r side of the table (even though extra quote characters will add four more bytes)

– pppery – 2017-08-07T19:09:06.473

3 more bytes saved (also you can replace the last return with print for another one) – Erik the Outgolfer – 2017-08-09T10:21:58.593

1@HalvardHummel The goal is reached; we are under 2000 bytes! – Jonathan Frech – 2017-08-11T00:12:15.593

@EriktheOutgolfer Since it now seems more likely than ever that our paths will diverge, I wanted to thank you for the over two years we both participated on PPCG. Farewell and happy golfing! – Jonathan Frech – 2019-10-26T18:31:20.470

4

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);}

Marcos

Posted 2017-03-13T21:49:22.347

Reputation: 171

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. – Jonathan Frech – 2017-08-14T03:57:28.027

If you add something like typedef int Q; and replace all occurrences of int with Q, you could save another 44 bytes. – Jonathan Frech – 2017-08-14T04:09:41.167