Perl, 293 bytes
-9 bytes thanks to @Dom Hastings
{$==7+rand 30;@r=$"=();@a=((C)x4,(E)x3,("#")x1369,(" ")x1369);for$i(0..7+rand 30){$r[$i][$_]=splice@a,rand@a,1for 0..$=}$r[0][$=]=F;$r[-1][0]=P;$_=$r=join$/,$v="#"x($=+=3),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say
Add -E
flag to run it:
perl -E '{$==7+rand 30;@r=$"=();@a=((C)x4,(E)x3,("#")x1369,(" ")x1369);for$i(0..7+rand 30){$r[$i][$_]=splice@a,rand@a,1for 0..$=}$r[0][$=]=F;$r[-1][0]=P;$_=$r=join$/,$v="#"x($=+=3),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say'
However, it takes a long time to run, so I recommend using this version instead:
perl -E '{${$_}=8+rand 30for"=","%";@r=$"=();@a=((C)x4,(E)x3,("#")x($v=rand $=*$%),(" ")x($=*$%-$v));for$i(0..$%-1){$r[$i][$_]=splice@a,rand@a,1for 0..$=-1}$r[0][$=-1]=F;$r[$%-1][0]=P;$_=$r=join$/,$v="#"x($=+=2),(map"#@$_#",@r),$v;1while$r=~s/F(.{$=})?[^#F]/F$1F/s||$r=~s/[^#F](.{$=})?F/F$1F/s;$r!~/[CEP]/&&/C.*C/s&&/E/?last:redo}say'
Try it online!
Explanation
{ # enter a block (which is used as a loop)
{$==7+rand 30; # randomly select the width of the map -2
# (-2 because we don't include the borders yet)
@r=$"=(); # reset @r, and set $" to undef
@a=( # create a list of the character that can be on the board
(C)x4, # 4 coins 'C'
(E)x3, # 3 enemies 'E'
("#")x1369, # 37*37 '#'
(" ")x1369); # 37*37 spaces
for$i(0..7+rand 30) # create the 2D map (7+rand 30 is the height, which is generated just now)
for$_(0..$=-1){
$r[$i][$_]= # index [$i][$_] receives ...
splice@a,rand@a,1 # .. a random character from the list previously generated
# (the character is then removed from the list thanks to 'splice')
}
}
$r[0][$=]=F; # add the finish cell
$r[-1][0]=P; # add the start cell
$_=$r= # here we generate a string representation of the map
join$/, # join the following elements with newlines
$v="#"x($=+=3), # a first line of # only
(map"#@$_#",@r), # add a # to the beginning and the end of each line
$v; # the last line of #
1while # the following regex will replace every accessible cell with a F
$r=~s/F(.{$=})?[^#F]/F$1F/s # a cell on the right or the bottom of a F cell is replaced
|| # or
$r=~s/[^#F](.{$=})?F/F$1F/s; # a cell on the left or the top of a F cell is replaced
$r!~/[CEP]/ # if there is no C, E or P on the map (meaning they were all accessible)
&& /C.*C/s # and there are at least 2 coins
&& /E/ ? # and 1 enemy
last: # the the map is valid, we exit the loop
redo # else, start over
}
say # and print the board
It takes a long time to run, because the list from which we randomly pick the characters to put on the board (@a
) contains 1369 whitespaces and #
, and only 4 coins and 3 enemies. So if the size of the width and height are small, there are a lot of spaces and #
compared to the coin and the enemies, so it's quite likely that a random map won't be valid. That's why the "optimized" version is faster: the list from which we pick the characters is just a little bigger than the map (the list is @a=((C)x4,(E)x3,("#")x($v=rand $=*$%),($")x($=*$%-$v))
: a random number $v
of #
(inferior to the size of the map), and size of the map - $v
whitespaces).
3It's roguelike, just fyi. – Rɪᴋᴇʀ – 2016-12-13T18:31:26.080
2Can you clarify "every possible combination should have an equal chance of occurring"? Do you literally mean that all the valid maps (in particular, all maps where P can reach all the C/E/Fs) must occur with equal probability? If so, it seems that the only possible algorithm is to generate maps uniformly at random and then check that P can reach everything, discarding invalid maps until that happens. – Greg Martin – 2016-12-13T19:15:55.843
Can you also clarify - "There should be some amount of walls in the middle", what if I place only 2 walls all the time? – Gurupad Mamadapur – 2016-12-13T19:17:32.847
1@GregMartin I'll change it too "Every possible layout should have a chance of occurring", not necessarily an equal chance. – Pavel – 2016-12-13T19:20:49.153
@GurupadMamadapur Then there will be valid layouts that your algorithm has no chance of generating. – Pavel – 2016-12-13T19:21:25.523
I think "some chance of occurring" is an improvement! Given that, I think you can delete "(You may assume your language's built in random number generator is uniformly random)" – Greg Martin – 2016-12-13T19:36:29.420
#######~#PCCEF#~#######
is the smallest possible? – Magic Octopus Urn – 2016-12-13T20:36:33.100@carusocomputing It has to be at least 10 by 10. – Pavel – 2016-12-13T20:57:27.110
The tricky part is paving a way from P to F ... I guess that should be random too? (That´s what
every possible layout
implies for me.) – Titus – 2016-12-13T23:47:04.647@Titus Every possible layout means every possible configuration of
#
,P
,F
,C
, andE
that fits the spec. So yes, the path can't be constant. – Pavel – 2016-12-13T23:51:32.8632What about unreachable empty squares surrounded by walls? Is it a valid layout or should they be avoided altogether? (In other words: should each empty square be reachable?) – Arnauld – 2016-12-14T10:19:34.113
@Arnauld no, empty squares can be unreachable and count as separate layouts. – Pavel – 2016-12-14T14:43:08.223
And can the player pass through coins and enemies? (by collecting / killing them) – Arnauld – 2016-12-14T14:51:36.180
@arnauld yes, he can. – Pavel – 2016-12-14T14:56:58.353