Simple redstone simulator

27

5

Redstone is a material in the game Minecraft, and it is used for many complex contraptions. For this program, you will only need to simulate three items: the redstone wire (noted with R), redstone torch (noted with T), and block (noted with B).

Here are a list of basic rules about how redstone works:

A redstone torch sends power to any adjacent redstone wire.
TRRRR
 ^This redstone wire is powered.

Redstone wire can only hold power for 15 blocks.
TRRRRRRRRRRRRRRRR
                ^This last wire is unpowered, because the torch is >15 blocks away.

A block is said to be powered if a powered redstone wire is found adjacent to it.
TRRRB
    ^This block is powered.

If a block next to a redstone torch is powered, then the torch stops emitting power.
T
R
R
R
B <This block is powered.
T <This redstone torch does not emit power because of the block next to it.
R <This redstone is unpowered because the torch is not providing power.
R

Input will be given in two dimensional arrays up to a size of 64x64, like this:

TRRR
   B
TBRTRR
R
RRRRRRRRR
        R
   RRRRRR

It is guaranteed that the input will not have any "clocks", or redstone powered by a torch pointing to the block that the torch is on. There will only be one redstone circuit in every input.

Your program must change each character to be a 1 or a 0, 1 indicating if this item is powered/emitting power, and a 0 if it is unpowered/not emitting power.

This input should have this output:

1111
   1
100000
1
111111111
        1
   001111

This is a code-golf, so shortest code wins, as always.

beary605

Posted 2013-01-29T04:53:08.883

Reputation: 3 904

1What output do you expect for situations like "TRR\nB B\nRRT"? – Howard – 2013-01-29T06:05:26.477

111\n0 1\n000 is the output; it seems to be sound within the rules. I will put an input restriction saying you cannot have any situations like TRR B R RRR, where it flashes repeatedly. – beary605 – 2013-01-29T06:22:41.730

1Can we assume that each input array will contain only one complete circuit running from top to bottom as in your example or do we have to code for multiple separate circuits starting anywhere in the array? – Graham – 2013-01-29T11:32:45.570

@Graham: There will only be one redstone circuit for each input. – beary605 – 2013-01-29T14:26:29.033

1Knowing the game Minecraft, I think that in your example given the block on line 2 does not stop the adjacent torch from giving power (the redstone doesn't actually connect to the block). Is this an error or a meant simplification? – tomsmeding – 2013-01-29T19:15:07.540

Also, can we expect a maximum input size for the array? – tomsmeding – 2013-01-29T21:36:22.630

@tomsmeding: simplification purposes. Maximum size? How about 64x64, that's nice :) – beary605 – 2013-01-30T00:19:35.843

Does whitespace after the end of the line matter in the output? Also, should the output end with a newline? – Quelklef – 2016-08-03T06:01:01.163

I must answer this in Minecraft... – HyperNeutrino – 2017-04-17T01:30:16.770

Answers

4

Python, 699

This is just a quick pass (ran out of time for now). It can probably use a lot more golfing.

import sys
m=[list(x)for x in sys.stdin.read().split('\n')]
e=enumerate
S=set
s=lambda x:S([(r,c)for r,i in e(m)for c,j in e(i)if j==x])
q=S()
t=s('T')
b=s('B')
n=s('R')
def d(o,r,c,i,h,q):
 if i<0:return 0
 o[(r,c)]=1
 for p in[(r+1,c),(r-1,c),(r,c+1),(r,c-1)]:
  if p in q or(p in b and not(r,c)in n):continue
  if(r,c)in b and p in t-q:
   x=S([p])
   q|=x
   o[p]=0
   return 1
  if p in h or not p in o:continue
  h|=S([p])
  if not d(o,p[0],p[1],i-1,h,q):return 1
g=1
while g:
 o=dict(zip(b,[0]*len(b))+zip(n,[0]*len(n))+zip(q,[0]*len(q)))
 g=0
 for x,y in t:
  if not(x,y)in q and d(o,x,y,15,S(),q):g=1
for p in o.keys():m[p[0]][p[1]]=o[p]
print"\n".join(map(lambda x:"".join(map(str,x)),m))

ESultanik

Posted 2013-01-29T04:53:08.883

Reputation: 1 078

Yep, for example, you could use f=set and create a l=lambda x:zip(x,[0]*len(x)). Well, you'd still be over 700 chars. Also, you left a useless space at ... or not (a,z)in o. – Morwenn – 2013-07-05T11:30:16.877

Do you need the space after your print statement? – Zacharý – 2017-04-16T21:16:57.000

@ZacharyT You're right. Thanks! – ESultanik – 2017-04-17T00:56:23.133

This was already said, but f=set would shave a few chars, and you have another useless character @ not (a,z)in o – Zacharý – 2017-04-17T01:28:34.957

Use tabs AND spaces for some indentation savings.

– mbomb007 – 2017-04-17T13:54:04.653

4

Python 2, 556 bytes

c=' 0';L=len;M=map;q=list;r='B';s='16';t='T';u='0';E=enumerate
b=[q(M(lambda x:x+[u,s][x==t],q(w[:-1])))+[c]*(64-L(w))for w in open('redstone.txt')]
k=lambda h,l,z:max(q(M(lambda x:[int((x or c)[1:]),0][l^((x or c)[0]==h)],z)))
def v(d=0):
 for e,f in E(b):
    for g,G in E(f):z=[e!=0and b[e-1][g],g<L(f)-1and f[g+1],e<L(b)-1and b[e+1][g],g and f[g-1]];j=G;i=j[0]+str([[s,u][k(r,1,z)>0],4,4,k(t,0,z),0,max(1,k(r,0,z))-1][ord(j[0])%7]);b[e][g]=i;d=d|(i!=j)
 return d
while v():0
for f in b:print''.join(M(lambda j:[' ',`int(j[1:]!=u)`][j[0]!=' '],f))+'\n'

See it in action

  • Assumes each line in input ends with a newline
  • Outputs via print()
  • Each line of output ends with lots of whitespace and a newline

  • Saved lots of bytes thanks to @mbomb007 (#34718)
  • Saved 1 byte thanks to @ZacharyT (#55550)

Quelklef

Posted 2013-01-29T04:53:08.883

Reputation: 441

You are not required to have input and output via files. You may use stdin and stdout, with input() and print. Also, str(int(bool(j[1:]!=u))) is the same as \int(j[1:]!=u)``. – mbomb007 – 2016-08-03T18:07:08.430

@mbomb007 Well, not quite, I still need the str(, but good point about bool(. – Quelklef – 2016-08-03T18:15:29.700

\x`` (using backticks, it's an alias for repr) is the same as str(x) (for small integers, at least. It's different for certain objects, longs, generators, etc). Another golf: if g!=0 is the same as if g. You can also have k=lambda h,l,z:max(... – mbomb007 – 2016-08-03T18:16:52.603

@mbomb007 Backticks are not for Py3, and I don't have 2 on this pc. If I install it or switch computers, I'll add that, thanks.

– Quelklef – 2016-08-03T18:19:32.300

Use an online interpreter, like https://repl.it or https://www.ideone.com. Then save it, and put the link in your answer. Then we can all try your code with the click of a button.

– mbomb007 – 2016-08-03T18:21:54.510

You should also view the Tips for golfing in Python page.

– mbomb007 – 2016-08-03T18:23:48.980

And on lines that are two spaces in (like f=b[e]), use a single tab instead of the two spaces. – mbomb007 – 2016-08-03T18:25:03.120

@mbomb007 I actually saw that page, was able to save some space but the double-for-into-one-for-loop didn't work for me. I'll change whitespace as soon as I can get it working on py2. – Quelklef – 2016-08-03T18:27:58.887

Let us continue this discussion in chat.

– mbomb007 – 2016-08-03T18:31:42.013

1Do you need the space here? print ''? Could it be print''? – Zacharý – 2017-04-16T21:14:30.980

4

Haskell, 400

import Data.Char
import Data.List
f x=[(++[x]).tail,(x:).init]
h(' ':_)=' '
h('T':s)=if elem 'b's then 'T'else 't'
h('t':s)=h$'T':s
h('B':s)=if any(`elem`s)['e'..'s']then 'b'else 'B'
h('b':s)=h$'B':s
h(_:s)=max 'd'$chr$ord(maximum s)-1
o ' '=' '
o c|elem c"dTB"='0'
o _='1'
a=(map.map)o.(!!(64^2+16)).iterate(map(map h.transpose).transpose.(\l->[g l|g<-id:f(map(const ' ')$head l)++map map (f ' ')]))

map(map h.transpose).transpose.(\l->[g l|g<-id:f(map(const ' ')$head l)++map map (f ' ')]) replaces each tile by a list of itself followed by its four neighbors, then maps that through h. h says for each tile how it reacts to neighbors: Torches turn off ('T' rather than 't') when there's a power block ('b') nearby, wires ('d' for dead through 's') imperfectly copy their most-powered neighbor (though cant get worse than dead), etc.

iterate repeats this step, (!!(64^2+16)) plucks out an iteration at which acyclic circuits are done converging, and I totally wrote it like that to give an intuitive bound, not to land at 400.

Gurkenglas

Posted 2013-01-29T04:53:08.883

Reputation: 141