Perl, 92 90 89 84 bytes
Includes +1 for -n
Give height on STDIN:
perl -M5.010 bolt.pl <<< 15
bolt.pl
:
#!/usr/bin/perl -n
map{$_=$;until$;=$_,s/.6|3.?/53|16*rand/eg,/3|6/>/36/;say y|3615|\\/ |r}(1x$_.6)x$_
Explanation
If you call the offset of the starting point 0 (a point is at the corner of a character box), then on the next row you can have gone left or right (or not) and can end up with points on offsets -1,1
. The next row gives -2,0,2
as possible offsets etc. They all differ by 2. If you then call the character to the lower left of a point even and the character to the lower right odd you can extend that to assigning even or odd to each character position on a row such that even and odd alternate (in fact the whole plane is tiled in a checkerboard pattern). An even position can have a /
or
, an odd position can have \
or
.
The character just before a /
is in an odd position so it could be either \
or
, but \/
is forbidden so only
is possible. Similarly the character after a \
must be a
(assuming the row is padded with enough spaces to the left and the right so the row boundaries are no issue). So a lightning bolt continues on the next row always directly below a \
or below a /
. In either case the lower point is in the middle and the next row can have one of
, /
, \
or /\
directly below the top 2 characters. So to generate the next row I can simply replace any \
or /
by any of these 4 expansions with equal probability (you could also independently replace the first character by
or /
and the second character by
or \
). In perl you could do this with something like:
s#\\ | /#(" "," \\","/ ","/\\")[rand 4]#eg
If the resulting row however contains \/
(forbidden join) or no /
or \
at all (bolt dies and does not reach the bottom) the result is invalid. In that case I throw away the whole row and simply try again. A valid continuation always exists and if you try often enough one will be found (e.g everything dies except for 1 flow). This is a slightly different probability distribution from the suggested anti-overlap algorithm, but I think this is in fact better since it has no directional bias. Validity can be testing in a golfish way using
m#\\|/#>m#\\/#
The problem here is that the random substitution is so looooong and all these \
escapes also eat bytes. So I decided to build my rows using strings of digits and replace the appropriate digits by
, /
and \
just before printing. The basic random replacement is
53|16*rand
which gives one of 53
, 55
, 61
or 63
with equal probability. I then interpret 5
and 1
as
, 3
as \
and 6
as /
. That explains the row print:
say y|3615|\\/ |r
In a serious golf competition I would now start to systematically explore alternative magic formulas, but this should be pretty good (within 3 bytes of optimal)
The rest of the components of the program:
1x$_.6
This initializes $_
(see the next map) to height spaces followed by a /
. This is an invisible row above the first one being printed and makes sure the field is wide enough so the bolt can never run out of space at the left
map{ ... ; say ...}(1x$_.6)x$_
I will process this same initial string height times printing a new row each time
$_=$;until$;=$_,...
Save the current row in $;
. If the replacement turns out to be invalid restore $_
from $;
s/.6|3.?/53|16*rand/eg
Do the actual substitution. I don't have to check what is before /
or after \
since it must be a space. This is convenient since space can be represented by either 1
or 5
. Since I only padded the string to the left the space after the \
can still be absent, so make that character optional
/3|6/>/36/
Check if the new row is valid
7
Stay safe and have fun golfing!
Maybe also specify that if EAS strikes, abandon everything and follow orders! Golfing code is not your priority in such a situation. – Erik the Outgolfer – 2016-10-07T16:36:10.21017@EriktheGolfer you are not a true golfer then. – Blue – 2016-10-07T16:51:14.833
4I don't believe that "The center-most path should be the one reaching the ground" is consistent with the rest of the random-generation description. For example, it's randomly possible for the original bolt to split twice and then for the middle two bolts to end; how can this possibility be overridden while still preserving the probabilities indicated? – Greg Martin – 2016-10-07T18:19:00.643
Also, what happens if (for example) the first two steps are both splits? Then the middle two bolts are touching each other, which seems problematic but also isn't ruled out by the special cases. – Greg Martin – 2016-10-07T18:19:47.387
@GregMartin Good point on the center-most part, originally I was hoping it to generate a balanced bolt, but now that I think about it even without that constraint about 50% of the time it should end up somewhere in the middle, a depth of 15 would only have 1-2% chance where the right or left most path lands. I'll remove that rule. And for the 2 steps splitting part, the only thing to prevent for is that no 2 paths should 2 paths join:
\/
at any point. – Zukaberg – 2016-10-07T18:31:24.910Ok on the first choice. But you should specify exactly what probabilities you want to occur to avoid the
\/
situation. – Greg Martin – 2016-10-07T18:47:40.657@GregMartin Because the order of the creation of the path is flexible as per last rule, i.e. if you create the left path first, then the left side of the split path would have the full probability 25/25/25/25, but then the right path would be limited to 50right/50end. I suppose one could argue that this would conflict with the original probability distribution, but since that rule is at the lowest priority, we would always want to adhere to these overlapping and dead end rules first if that makes sense. – Zukaberg – 2016-10-07T18:58:05.070
I'm sure there is a way of phrasing it so that it makes sense. I'm just pointing out that you need to do so :) – Greg Martin – 2016-10-07T19:10:38.413
Is any amount of whitespace to the left and the right of the bolt allowed ? – Ton Hospel – 2016-10-07T19:45:33.347
@TonHospel The left white spaces should be added such that the line above connects with the next one, however the white spaces to the right are not restricted – Zukaberg – 2016-10-07T20:08:52.907
@Zukaberg I understand that. But can I add the same amount of of whitespace in front (and possibly after) every line so that the whole bolt is shifted to the right. This is relevant for a top down construction so the bolt cannot get too wide – Ton Hospel – 2016-10-07T20:23:58.240
@TonHospel I've added a new rule that the left whitespaces (the amount that the whole structure is shifted to the right) must be less than the width of your structure – Zukaberg – 2016-10-07T20:28:51.803
@Zukaberg That's not very useful since the bolt structure can be only 1 wide if you are (un)lucky. What I'm obviously looking for is starting with as many white spaces as the height of the structure-1 – Ton Hospel – 2016-10-07T20:31:32.330
@TonHospel I suppose it would be reasonable to allow that, the challenge's focus is not on this minor detail, if it means better focus on the actual bolt structure sure I don't mind that – Zukaberg – 2016-10-07T20:42:01.260