25
\$\begingroup\$

We seem to never get tired of alphabet-related challenges...


The recipe

Given

  • a string of letters S, and
  • two positive integers M, N,

produce an alphabet soup with the letters of S occupying random positions in a rectangular bowl of size M×N, framed by a non-alphabetic, non-space character to represent the rim of the bowl.

Positions not used by letters should be displayed as spaces. See the examples below.

Aditional rules

  • The size M×N refers to the interior of the bowl. The size including the rim is M+2×N+2.
  • Each character from S should appear once in the bowl, in a different position; that is, one character cannot overwrite another.
  • S may contain duplicates. For instance, if S is the string 'abcc', the soup must contain one a, one b, and two c (all in different positions).
  • The inputs will satisfy the restrictions M >= 1, N >= 1, 1 <= length(S) <= M*N.
  • The rim of the bowl can be any non-alphabetic, non-space character, consistent across program runs and input values.
  • Letter positions in the bowl are random, so the result may differ every time the program is run with the same inputs.
  • Given the input, every possible set of letter positions should have a non-zero probability. Since this cannot be checked from a few realizations of the program, please explain how your code fulfills this.
  • Leading or trailing whitespace around the rim is allowed.
  • S will contain are only uppercase letters. If wou wish, you can choose to take only lowercase letters.
  • Input and output are flexible as usual. For example, the output can be a string with newlines, a 2D character array, or a list of lines.
  • Programs or functions are allowed, in any programming language. Standard loopholes are forbidden.
  • The shortest code in bytes wins.

Examples

Inputs are shown as S, [M N], where M is number of rows and N is number of columns. The character # is used for the rim.

'O', [1 1]:

###
#O#
###

'HEY', [1 3]:

#####
#YHE#
#####


'HELLO', [4 11]:

#############
#  O        #
#         H #
#    LE     #
#   L       #
#############


'ADVNJSGHETILMVXERTYIOJKCVNCSF', [8 12]:

##############
#K  V  L   S #
# A   V  X H #
#T    M C    #
# I       O N#
#  YC        #
# G  I   R SE#
#   J      F #
#JT  D  V EN #
##############


'OOOOOOOOOOXXXXX', [13 31]:

#################################
#    X                          #
#                O              #
#                               #
#                  X            #
#                        O      #
#             X           O     #
#      O                        #
#         X                     #
#                        O      #
#       X                       #
#                    O          #
#  O      O      O              #
#                             O #
#################################


'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ', [11 41]

###########################################
#                                       JU#
#     Q         C M    G     R T U Y  H   #
#  KI          E   H    M   YO            #
#      V BW        I    JC                #
#     SV           D     P   B          U #
#           A     F    RF   J  KP E       #
#            E   N      TH        Z       #
#    N  BM  O     Q   I        AS N  WX   #
#   S     O  K       G L       P       Q  #
#Z     L T         R   L       A      F DD#
#      V   Y           WX   C       G XZ  #
###########################################
\$\endgroup\$
5
  • \$\begingroup\$ Loosely related \$\endgroup\$
    – Luis Mendo
    Oct 3, 2019 at 8:40
  • \$\begingroup\$ "Letter positions in the bowl are random, [...]" <-- do you mean can be random or must be random? And can all lines have the same number of chars, all the time? \$\endgroup\$ Oct 3, 2019 at 17:21
  • \$\begingroup\$ @IsmaelMiguel Must. And every configuration must have a nonzero probability of occurring (stated in the challenge). So that rules out the -always-same-length approach \$\endgroup\$
    – Luis Mendo
    Oct 3, 2019 at 17:25
  • \$\begingroup\$ Can the rim be consistent across program runs and input values, but use multiple non-letters, e.g. drawing an ASCII art border with |+-? \$\endgroup\$
    – Adám
    Oct 3, 2019 at 17:45
  • \$\begingroup\$ @Adám Hm I’m going to say no, that’s too big a change \$\endgroup\$
    – Luis Mendo
    Oct 3, 2019 at 19:12

25 Answers 25

13
\$\begingroup\$

05AB1E, 20 18 16 15 14 bytes

*j.rS²ô2Føε8.ø

Takes three inputs in the order: height, width, string. Output as a 2D list of characters.
Uses 8 as border, but could be any digit.

-1 byte thanks to @Grimy.

Try it online or verify all test cases. (TIO contains }}J» in the footer to pretty-print the result; feel free to remove it to see the actual output 2D list of characters instead.)

Explanation:

*               # Multiply the (implicit) width and height inputs
 j              # Pad the (implicit) input-string with up to that amount of leading spaces,
                # so the total string-length is equal to that value
  .r            # Shuffle the characters in the string
    S           # Convert the string to a list of characters
                # (edge-case for the zip below with strings of size 1 with 1x1 dimensions)
     ²          # Push the width input again
      ô         # Split the list of characters into parts of that size
       2F       # Loop 2 times:
         ø      #  Zip/transpose the 2D list; swapping rows/columns
          ε     #  Inner map over each line:
           8.ø  #   And surround this line-list with a leading/trailing "8"
                # (after the loop, the result is output implicitly)
\$\endgroup\$
3
  • 1
    \$\begingroup\$ @LuisMendo I actually just say the challenge 3 minutes ago. ;) It's a pretty straight-forward implementation. Will try to golf it down from here. \$\endgroup\$ Oct 3, 2019 at 8:56
  • 1
    \$\begingroup\$ Very nice, I didn't think about *j! Here's 13 for legacy, or an ugly 14 for modern (outputs a 2D character array). \$\endgroup\$
    – Grimmy
    Oct 3, 2019 at 11:59
  • 1
    \$\begingroup\$ @Grimy The 13-byter seems to fail for input 1,1,"O", so I think it has to be the 14-byter for the legacy as well. Thanks for -1 though. \$\endgroup\$ Oct 3, 2019 at 12:08
7
\$\begingroup\$

APL (Dyalog Unicode), 25 bytesSBCS

'#',∘⌽∘⍉⍣4{⍵⍴⊃¨↓∘⍺¨?⍨×/⍵}

Try it online!

-22 thanks to @ngn, -7 thanks to @ngn and @Adám

Explanation:

'#',∘⌽∘⍉⍣4{⍵⍴⊃¨↓∘⍺¨?⍨×/⍵}
          {            ⍵} ⍝ Function that generates the content
                          ⍝  argument: ⍵ (width and height), ⍺ (string)
                     ×/   ⍝ get the product
                   ?⍨     ⍝ For each randomized elements
               ↓∘⍺¨       ⍝ take the character in ⍺
           ⍵⍴⊃¨           ⍝ turn it back into a matrix of shape ⍵
    ∘ ∘ ⍣4                ⍝ Then, 4 times, do these 3 things:
'#',                      ⍝ - prepend a # to the axis
     ⌽                    ⍝ - reverse the columns
       ⍉                  ⍝ - swap columns and lines

APL (Dyalog Extended), 21 bytesSBCS

The rim's angles are different characters

{⌂disp⊂⍵⍴⊃¨↓∘⍺¨?⍨×/⍵}

Try it online!

Using the dfn to display the box.

\$\endgroup\$
5
  • \$\begingroup\$ 29: '#',∘⌽∘⍉⍣4⊢⍴∘(?⍨∘≢⊃¨⊂)↑⍨∘(×/) Try it online! \$\endgroup\$
    – Adám
    Oct 3, 2019 at 10:19
  • \$\begingroup\$ 28: {'#',∘⌽∘⍉⍣4⊢⍵⍴⍺\⍨(≢⍺)>?⍨×/⍵} (or instead of > if ⎕io=1) \$\endgroup\$
    – ngn
    Oct 3, 2019 at 10:35
  • \$\begingroup\$ actually, 27: '#',∘⌽∘⍉⍣4{⍵⍴⍺\⍨(≢⍺)>?⍨×/⍵} \$\endgroup\$
    – ngn
    Oct 3, 2019 at 10:42
  • 3
    \$\begingroup\$ 25: '#',∘⌽∘⍉⍣4{⍵⍴⊃¨↓∘⍺¨?⍨×/⍵} \$\endgroup\$
    – ngn
    Oct 3, 2019 at 10:51
  • \$\begingroup\$ Regarding the 21 \$\endgroup\$
    – Adám
    Oct 3, 2019 at 19:13
6
\$\begingroup\$

Python 3, 110 bytes

lambda s,m,n,r=['#']:[r+(n*r+[i for i,j in{*zip(s+m*n*' ',range(m*n))}]+n*r)[k*n:-~k*n]+r for k in range(m+2)]

Try it online!

Randomizes by using a set comprehension and returns a 2D character array.

\$\endgroup\$
6
  • \$\begingroup\$ Nice use of set comprehension to randomize. +1. But your codes relies on the name 'f' of the function. Therefore I think the lambda solution isn't valid... \$\endgroup\$
    – agtoever
    Oct 3, 2019 at 16:41
  • 1
    \$\begingroup\$ @agtoever Thanks! The function is not recursive, so it can be anonymous. Are you referring to the f'{s:{m*n}}' part? Because that is the syntax for a formatted string, which just coincidentally also happens to start with an f. \$\endgroup\$
    – Jitse
    Oct 3, 2019 at 17:24
  • 3
    \$\begingroup\$ This code seems to violate PEP 8 in several ways. \$\endgroup\$ Oct 4, 2019 at 13:22
  • 1
    \$\begingroup\$ @Christofer-Ohlsson absolutely! \$\endgroup\$
    – Jitse
    Oct 4, 2019 at 18:48
  • 2
    \$\begingroup\$ @ChristoferOhlsson Welcome to the world of code-golf, haha. ;) No comments/docs whatsoever; single character variables/methods without any (unnecessary) spaces/newlines; potentially hundreds of compiler-warnings we simply ignore; increasing performance from O(log(N)) to O(N^N); etc. If it can save even a single byte, it's all fine and totally worth it for code-golfing. ;) \$\endgroup\$ Oct 7, 2019 at 12:30
5
\$\begingroup\$

Bash + coreutils, 139 125 characters

r=`printf %$3s@@|tr \  @`
echo $r
printf %$[$2*$3]s $1|fold -1|shuf|tr -d \\n|fold -$3|paste -d@ <(:) - <(:)|head -$2
echo $r

Sample run:

bash-5.0$ bash soup.sh HELLO 4 11
@@@@@@@@@@@@@
@  H        @
@      OE   @
@    L      @
@          L@
@@@@@@@@@@@@@

Try it online!

Bash + coreutils + boxes, 97 characters

printf %$[$2*$3]s $1|fold -1|shuf|tr -d \\n|fold -$3|boxes -dsimple -s$[$3+2]x$[$2+2] -pa0 -itext

Sample run:

bash-5.0$ set -- HELLO 4 11

bash-5.0$ printf %$[$2*$3]s $1|fold -1|shuf|tr -d \\n|fold -$3|boxes -dsimple -s$[$3+2]x$[$2+2] -pa0 -itext
*************
* O   L  E  *
*      H    *
*           *
*     L     *
*************

Try it online! (Partially, as boxes is not installed on TIO.)

\$\endgroup\$
5
\$\begingroup\$

J, 30 29 bytes

-1 byte thanks to Jonah

'#'|.@|:@,^:4[$*/@[(?~@[{{.)]

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Because TIO uses a fixed random seed. 9!:1]6!:9'' fixes that \$\endgroup\$
    – Adám
    Oct 3, 2019 at 12:32
  • 2
    \$\begingroup\$ Really like the way used the zero fill of {.. Slight tweak for 29 '#'|.@|:@,^:4[$*/@[(?~@[{{.)]: Try it online! \$\endgroup\$
    – Jonah
    Oct 4, 2019 at 2:08
5
\$\begingroup\$

PowerShell, 163 111 93 bytes

param($w,$h,$s)'#'*$w+-join($s|% *ht($w*$h)|% t*y|sort{Random})+'#'*$w-replace".{$w}",'#$0#
'

Try it online!

Takes input as $width, $height, $string.

Constructs a string of # of the appropriate $width, string-joins that with some computation, and then that same # string again. The computation starts with taking the input $string, and doing a .padRight up to the $width by $height length (i.e., make a string long enough to completely take up the rectangular space. We then convert that string toCharArray, and sort it Randomly. That gives us the mixed-up middle portion. Finally, we -replace it into chunks of equal $width, and surround those chunks with #s.

-52 thanks to inspiration from AZTECCO
-18 bytes thanks to mazzy

\$\endgroup\$
3
  • \$\begingroup\$ You have 2 x random (12) while JS has one, he added spaces to fill M*N size and sorted, after that you still pay 21 for '$' unfortunately \$\endgroup\$
    – AZTECCO
    Oct 4, 2019 at 5:56
  • 1
    \$\begingroup\$ @AZTECCO Thanks for the inspiration! \$\endgroup\$ Oct 4, 2019 at 13:04
  • \$\begingroup\$ Thanks @mazzy - very clever with the -replace instead of splitting and joining. \$\endgroup\$ Oct 7, 2019 at 12:58
4
\$\begingroup\$

JavaScript (ES7), 125 bytes

Returns a string. Uses 0 as the frame character.

(s,h,w)=>(a=[...s.padEnd(w++*h++)].sort(_=>Math.random()-.5),g=x=>y+~h?(x%w&&y%h&&a.pop())+[`
`[x-w]]+g(x<w?x+1:!++y):a)(y=0)

Try it online!

Commented

(s, h, w) => (               // s = string; h = height; w = width
  a =                        // build an array a[] consisting of:
    [...s.padEnd(w++ * h++)] //   all original characters in s padded with spaces for a
    .sort(_ =>               //   total length of w * h, in a random order
      Math.random() - .5     //   (this is not guaranteed to be uniform, but it is not
    ),                       //   required to be)
  g = x =>                   // g is a recursive function taking x:
    y + ~h ?                 //   if we haven't reached the end of the grid:
      ( x % w &&             //     if we're not located on a vertical border
        y % h &&             //     nor on a horizontal border,
        a.pop()              //     extract the last character from a[]
      ) +                    //     (otherwise, append '0')
      [`\n`[x - w]] +        //     if we've reached the end of the row, append a linefeed
      g(                     //     append the result of a recursive call:
        x < w ? x + 1 : !++y //       using either (x+1, y) or (0, y+1)
      )                      //     end of recursive call
    :                        //   else (end of grid):
      a                      //     a[] is now empty and can be used as an empty string
)(y = 0)                     // initial call to g with x = y = 0
\$\endgroup\$
4
\$\begingroup\$

APL (Dyalog Extended), 23 bytesSBCS

Anonymous tacit infix function. Takes [M,N] as left argument and S as right argument.

'#',∘⌽∘⍉⍣4⊣⍴×/⍛(?⍨⍤⊣⊇↑)

Try it online!

×/⍛() apply the following function between the arguments, replacing the left argument with its product:

 take M×N characters from S, padding with spaces on the right

 reorder that to the following order:

?⍨⍤ the shuffled indices 1 through…
 the left argument (M×N)

reshape that to the following shape:

 the left argument (i.e. M rows and N columns)

'#'⍣4 apply the following function four times, each time with the hash character as left argument:
∘⍉ transpose the right argument
∘⌽ mirror the right argument
, concatenate a column of hashes to the left side of that

\$\endgroup\$
4
\$\begingroup\$

PHP 7.4, 107 99 94 characters

fn($s,$r,$c)=>_.chunk_split(($b=str_pad(_,$c,_)).str_shuffle(str_pad($s,$r*$c)),$c,"_
_").$b._

Thanks to:

  • Ismael Miguel for reminding me about PHP 7.4's arrow functions (-10 characters)
  • Night2 for efficiently reversing the concatenations and the join() (-8 characters)
  • Night2 for showing how to use chunk_split()'s $end parameter (-5 characters)

Try it online!

PHP 7.3, 117 112 108 characters

function s($s,$r,$c){echo _.chunk_split(($b=str_pad(_,$c,_)).str_shuffle(str_pad($s,$r*$c)),$c,"_
_").$b._;}

Thanks to:

  • Night2 for efficiently reversing the concatenations and the join() (-5 characters)
  • Night2 for showing how to use chunk_split()'s $end parameter (-4 characters)

Sample run:

php > function s($s,$r,$c){echo _.chunk_split(($b=str_pad(_,$c,_)).str_shuffle(str_pad($s,$r*$c)),$c,"_
php " _").$b._;}
php > s('HELLO', 4, 11);
_____________
_  L        _
_        L  _
_E          _
_    OH     _
_____________

Try it online!

\$\endgroup\$
7
  • 1
    \$\begingroup\$ I believe that fn($s,$r,$c)=>($b=str_repeat(9,$c+2))."\n9".join("9\n9".str_split(str_shuffle(str_pad($s,$r*$c)),$c))."9\n$b"; should work in PHP 7.4 (wiki.php.net/rfc/arrow_functions_v2), and a release canditate has been released (wiki.php.net/todo/php74), so, it is an available "compiler" that came before this challenge, and anyone can use it. \$\endgroup\$ Oct 3, 2019 at 17:30
  • 1
    \$\begingroup\$ Doh, you are right. Read about, but forgot. (Note to myself: next time not just read Night2's tip. Upvote it too, maybe helps remembering.) \$\endgroup\$
    – manatwork
    Oct 3, 2019 at 17:58
  • 2
    \$\begingroup\$ 99 bytes \$\endgroup\$
    – Night2
    Oct 4, 2019 at 9:08
  • 1
    \$\begingroup\$ Thank you, @Night2. I can't imagine what I messed yesterday, as I tried moving more stuff inside the join(), but failed to reduce the size. ☹ \$\endgroup\$
    – manatwork
    Oct 4, 2019 at 18:34
  • 1
    \$\begingroup\$ Got even a shorter one using chunk_split: 94 bytes I also removed the last semicolon as I believe it is not needed, you have written a function, so the code which is going to assign it to a variable shouldn't count. \$\endgroup\$
    – Night2
    Oct 4, 2019 at 18:57
3
\$\begingroup\$

MATL, 22 19 bytes

tZ"ibpyn&Z@(TT35&Ya

Try it online!

Thanks @LuisMendo for saving 3 bytes, so now it has the same bytecount as @flawr's answer, but sufficiently different to post anyway. High-level agorithm overview:

 Z"                  % Create n x m matrix of spaces
           (         % Index into this matrix:
   i                 %  The alphabet vermicelli (explicit input)
        &Z@          %  at a random locations (randperm), which are
      yn             %   length(S) numbers, ranging
t   bp               %   from 1 to n*m
            TT35&Ya  % And finally add a border
\$\endgroup\$
2
  • \$\begingroup\$ You can change Z}&O by Z", and that also allows you to remove the final c \$\endgroup\$
    – Luis Mendo
    Oct 3, 2019 at 14:13
  • \$\begingroup\$ @LuisMendo Oh that helps a lot! Come to think of it, I should've at least done 1$O. \$\endgroup\$
    – Sanchises
    Oct 3, 2019 at 14:17
3
\$\begingroup\$

Ruby, 121 bytes

Creates the bowl, queries the indices of all spaces within the bowl, samples a number of spaces equal to the size of the string, and fills them in. sample does not return a sorted list, so there is no need to shuffle. Searching indices up to 9*m*n (which almost certainly goes out of range) will still get all spaces and is 1 byte shorter than r.size.

->s,m,n{r=[t=?@*(n+2),*["@#{' '*n}@"]*m,t]*$/;i=-1;(0..9*m*n).select{|j|r[j]==' '}.sample(s.size).map{|j|r[j]=s[i+=1]};r}

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Red, 120 116 114 112 bytes

-2 bytes thanks to @Kevin Cruijssen!

func[s m n][random pad s m * n insert/dup t: copy"00"0 n
print t loop m[print rejoin[0 take/part s n 0]]print t]

Try it online!

\$\endgroup\$
3
  • 2
    \$\begingroup\$ -2 bytes by getting rid of the + 1 and using to"""00"0 n instead. \$\endgroup\$ Oct 3, 2019 at 9:50
  • 1
    \$\begingroup\$ @KevinCruijssen Thanks! I replaced it with copy, for the same byte count. \$\endgroup\$ Oct 3, 2019 at 10:10
  • 1
    \$\begingroup\$ That indeed looks a bit cleaner! I don't know Red except for the answers I've seen from you, so I was just fiddling around a bit. ;) Would putting the t line as leading/trailing item before looping to save on the two loose print t be shorter? I doubt it, but since I don't know how to add items to a list I'm not sure. \$\endgroup\$ Oct 3, 2019 at 11:22
3
\$\begingroup\$

Perl 6, 74 67 bytes

-5 bytes thanks to Jo King

{0 X~0 x$^n,|comb($n,[~] $^s.comb[pick *,^$^m*$n]X//' '),0 x$n X~0}

Try it online!

Explanation

{                                                                 }
                                         ^$^m*$n  # Range 0 .. M*N-1
                                  pick *,  # Shuffle
                         $^s.comb  # Split S into chars
                                 [              ]  # Pick shuffled elements
                                                 X//' '  # undef to space
                     [~]  # Join
             # Split into n-character strings
             comb($n,                                  )
            |  # Flatten
     # Add top and bottom of bowl
     0 x$^n,                                            ,0 x$n
 # Add left and right of bowl
 0 X~                                                          X~0
\$\endgroup\$
1
  • \$\begingroup\$ 69 bytes \$\endgroup\$
    – Jo King
    Oct 4, 2019 at 3:22
3
\$\begingroup\$

T-SQL 2017, 232 bytes

Testing this online is an older version of sql-server costing another character. I posted the shorter version.

Golfed:

DECLARE @ varchar(max)=''SELECT top 999 @+=substring(@i,number+1,1)FROM spt_values
WHERE type='P'and number<@a*@b
ORDER BY newid()WHILE-@b<1SELECT @=stuff(@+' ',@b*@a+1,0,'#
#'),@b-=1PRINT stuff(replicate('#',2+2*@a),2+@a,0,trim(@))

Try it online

Ungolfed:

DECLARE @ varchar(max)=''

SELECT top 999 @+=substring(@i,number+1,1)
FROM spt_values
WHERE type='P'and number<@a*@b
ORDER BY newid()

WHILE-@b<1
SELECT @=stuff(@+' ',@b*@a+1,0,'#
#'),@b-=1
PRINT stuff(replicate('#',2+2*@a),2+@a,0,trim(@))
\$\endgroup\$
3
\$\begingroup\$

Perl 5 -lF, 99 97 bytes

-2 bytes courtesy of @NahuelFouilleul

%k=map{$_=>$F[$_]||$"}0..($m=<>)*($n=<>)-1;say+($p='#'x($n+1)),map"#
#"x!($i++%$n).$_,values%k,$p

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ ($i++%$n==0) could be changed by !($i++%$n) \$\endgroup\$ Oct 4, 2019 at 8:17
3
\$\begingroup\$

k4, 32 28 bytes

{4{|+x,'"#"}/y#a?(a:-*/y)$x}

edit: -4 thanks to Galen Ivanov!

called like

f["hey";3 3]

explanation:

                 (a:-*/y)    / neg product of y and assign to a 
                         $x  / left pad x so we have char vector the length of the inner area
               a?            / take `a` random drawings. if a is negative, draw with no duplicates/replacements
             y#              / reshape to y's dimensions
 4{        }/                / do {} 4 times 
   |+x,'"#"                  / append "#" along right-side of x then transpose (+) and reverse (|)
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I think you can save some bytes if you only append # at the end of each line and transpose/reverse 4 times, something like this. \$\endgroup\$ Oct 7, 2019 at 8:54
  • 1
    \$\begingroup\$ @GalenIvanov nice, updated! \$\endgroup\$
    – scrawl
    Oct 7, 2019 at 11:06
3
\$\begingroup\$

Java (JDK), 180 178 bytes

Not a single extra import:

(y,m,n)->{for(m*=n;y.length()<m;y+=" ");var s="";for(;m-->0;y=s)for(var c:y.split(s=""))s=Math.random()<.5?s+c:c+s;s="#".repeat(n);return(s+y+s).replaceAll(".{"+n+"}","\n#$0#");}

Try it online!

It was quite the struggle to get this golfed down. In particular, the imports involved with Collections.shuffle()/Arrays methods were too much to accept, so I had to create my own String shuffling algorithm (probably neither efficient nor uniformly distributed). Massive thanks to Steven for proving any set of positions can be generated from the algorithm.

Formatted (with explanation):

(y, m, n) ->                                                   // y = yummies in the soup,
{                                                              // m = height, n = width
    for (m *= n; y.length() < m; y += " ")                     // set m to m*n and
        ;                                                      // add spaces to y to fill up
    var s = "";                                                // the rest of the soup
    for (; m-- > 0; y = s)                                     // for m*n iterations, scramble y
        for (var c : y.split(s = ""))                          // with random appends
            s = Math.random() < .5 ? s + c : c + s;
    s = "#".repeat(n);                                         // create the top/bottom of the rim
    return (s + y + s).replaceAll(".{" + n + "}", "\n#$0#"); // add all sides of the rim
};
\$\endgroup\$
2
  • \$\begingroup\$ Nice answer! +1 from me. One small thing to golf: .replaceAll("(.{"+n+"})","\n#$1#") can become .replaceAll(".{"+n+"}","\n#$0#") \$\endgroup\$ Oct 6, 2019 at 9:36
  • \$\begingroup\$ @KevinCruijssen Thanks for the improvement :) \$\endgroup\$
    – Avi
    Oct 7, 2019 at 15:36
2
\$\begingroup\$

Charcoal, 27 bytes

NθNη↖B⁺²θ⁺²η#FS«W℅KKJ‽θ‽ηPι

Try it online! Link is to verbose version of code. Takes input in the order width, height, string. Explanation:

NθNη

Input the width and height.

↖B⁺²θ⁺²η#

Frame the bowl.

FS«

Loop over the characters in the string.

W℅KKJ‽θ‽η

Jump to a random position in the bowl until an empty spot is found.

Pι

Print the current character without moving the cursor.

\$\endgroup\$
3
  • \$\begingroup\$ Is that Move(:UpLeft) necessary? It works fine without it, but maybe you've added it for a reason I don't think about? \$\endgroup\$ Oct 3, 2019 at 9:28
  • 1
    \$\begingroup\$ @KevinCruijssen Without it I would never be able to write letters into the bottom row or rightmost column. \$\endgroup\$
    – Neil
    Oct 3, 2019 at 10:01
  • \$\begingroup\$ Ah, so that was it. That explains it, thanks! \$\endgroup\$ Oct 3, 2019 at 11:20
2
\$\begingroup\$

Japt -R, 21 18 bytes

úV*W ö¬òW ²Ô²û2W+2

Try it

úV*W ö¬òW ²Ô²û2W+2     :Implicit input of string U=S and integers V=M & W=N
úV*W                   :Right pad U with spaces to length V*W
     ö¬                :Random permutation
       òW              :Split to array of strings of length W
          ²            :Push 2
           Ô           :Reverse
            ²          :Push 2
             û2W+2     :Centre pad each element with "2" to length W+2
                       :Implicit output, joined with newlines
\$\endgroup\$
2
\$\begingroup\$

MATL, 29 27 19 bytes

pZ@iy~hw)1GeTT35&Ya

Try it online!

Thanks @LuisMendo for -8 bytes!

Explanation: p computes the number of soup-pixels. Then Z@ produces a random permutation of size of number of soup pixels. We will use this as indices to iy~h which is the input string with enough spaces added. w) swaps the two and indexes one with the other. We then reshape 1Ge the shape into the desired rectangle and #-pad it using TT35&Ya.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Clever! My attempt was 22 bytes \$\endgroup\$
    – Sanchises
    Oct 3, 2019 at 13:48
  • 2
    \$\begingroup\$ @Sanchises Go post it anyway! \$\endgroup\$
    – flawr
    Oct 3, 2019 at 13:50
2
\$\begingroup\$

Icon, 136 133 131 118 bytes

procedure f(s,n,m)
s||:=repl(" ",m*n-*s)
!s:=:?s&\z
write(t:=repl(0,m+2))
write(0,s[1+(0to n)*m+:m],0)&\z
write(t)
end

Try it online!

\$\endgroup\$
2
\$\begingroup\$

C (clang), 169 ... 156 bytes

i,b;f(n,m,s)char*s;{char o[b=i=-~++n*(m+=3)],*a=o;for(srand(&a);--i;)*a++=i%m?-~i%m<3|i<m|i>m*n?35:32:10;for(*a=0;*s;*a=*a-32?*a:*s++)a=o+rand()%b;puts(o);}

Try it online!

Saved 7 @ceilingcat suggestion to use -~variable and auto storage for string o plus many improvements.

Saved 4 again from @ceilingcat

Degolf :

char*a,// pointer for set operations 
*o=malloc(b=i=(m+=3)*(n+=2));  => o[b=i=(m+=3)*-~++n]
// before allocating for the whole bowl as a char array
// increments m by 3 (2 for rims and 1 for '\n') and n by one but allocates for 2(rims)
// and assigns bowl size to i and b.
srand(time(0));// seeds rand function 
for(// loop to make empty bowl 
a=o;// using pointer as iterator
 --i ;)//  i decremented as a counter

 *a=// sets every char to..
 i%m?// if(not) over right side of bowl (m+3)
   -~i%m<3|i<m|i>m*n-m?35// if on rim '#'//-~i == (i+1)
   :32 // else ' ' 
  :10;// i%m==0

for(*a=0;// before loop terminates bowl with \0
 *s;// for every letters(exit on '\n')
 *a=*a-32?*a:*s++)
 // puts letter if bowl at a is a space and
 // go to next letter

 a=o+rand()%b; 
 // sets a to o offsetted by random

puts(o);// prints bowl 
\$\endgroup\$
0
1
\$\begingroup\$

Jelly, 16 bytes

P⁶ẋaẊs⁸ṪṾ€«”~ZƊ⁺

A dyadic Link accepting a list of integers, [M, N], on the left and a list of characters, S, on the right which yields a list of lists of characters, the lines. Uses the tilde character, ~, as the border.

Try it online!

All possible outputs have a non-zero chance of being yielded since we shuffle () a list of the characters of S along with the appropriate number of spaces.

The code Ṿ€«”~ZƊ⁺ saves the byte which I imagine would be required to join with newlines that full programs using an integer such as zero would need to employ (e.g. P⁶ẋaẊs⁸Ṫ;€0ZUƊ4¡Y or P⁶ẋaẊs⁸Ṫj@€Ø0Z$⁺Y). Maybe there's a way to save more...?

\$\endgroup\$
1
\$\begingroup\$

C# (.NET Core), 274 bytes

[Without LINQ]

Embarrassing number of bytes, but, this is what I got.

(x,y,z)=>{var f=new string('#',x+2)+'\n';char[] b=new string(' ',y*x).ToCharArray();Random r=new Random();while(z.Length>0){var d=r.Next(0,y*x);if(b[d]==' '){b[d]=z[0];z=z.Substring(1);}}z=f;for(var j=1;j<y*x+1;)z+=(j%x==1?"#":"")+b[j-1]+(j++%(x)==0?"#\n":"");return(z+=f);}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Ruby, 105 78 bytes

Takes an array of characters and two integers; returns a string.

->s,h,w{((e=?#*w)+(s+[" "]*(h*w-s.size)).shuffle*""+e).gsub /.{#{w}}/,'#\&#
'}

Attempt This Online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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