66
\$\begingroup\$

Usually, it is said that "Doing X without Y" can be a trap to beginners writing challenges (source). However, I am cocky and think that I can definitely make an X without any Ys. Randomly. Oh yes, this will be good.

Challenge: Given an odd integer n greater than or equal to 1, output an ex of side length n made of random printable ascii characters sans "y" and "Y", and the space. All allowed characters must have a nonzero chance of occurring, but not necessarily uniform. This is a so the shortest code in bytes wins. You should, however, randomize each char--that is, the struts of the ex shouldn't be equal, unless if by chance.

The chars to appear

!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXZ[\]^_`abcdefghijklmnopqrstuvwxz{|}~"

Constructing the ex

Side length 1:

x

Side length 3:

x x
 x
x x

Side length 5:

x   x
 x x
  x
 x x
x   x

etc.

Example outputs

input
output
empty line

3
h 2
 ^
9 5

1
:

5
D   1
 W z
  W
 q j
W   1

Example implementation

You do not need to handle invalid inputs.

function generate(sideLength){
    var result = "";
    var INNER = "@"
    for(var i = 0; i < sideLength; i++){
        var p = i < sideLength / 2 ? i : sideLength - i - 1;
        result += " ".repeat(p) + ((sideLength / 2 | 0) == p ? "" : INNER) + " ".repeat(Math.max(sideLength - p * 2 - 2, 0)) + INNER + "\n";
    }
    
    return result.replace(RegExp(INNER, "g"), function(e){
        let c = "y";
        while(c === "y" || c === "Y"){
            c = String.fromCharCode((Math.random() * 94) + 33 | 0);
        }
        return c;
    });
}

function print(v){
    output.innerHTML = "";
    output.appendChild(document.createTextNode(v));
}

function update(){
    var n = Number(input.value);
    if(n !== Math.floor(n)) print("error: " + n + " is not an integer.");
    else if(n % 2 === 0)    print("error: " + n + " is not odd.");
    else if(n < 1)          print("error: " + n + "is less than one.");
    else                    print(generate(n));
}

input.onchange = update;

update();
* {
  font-family: Consolas, monospace;
}

#output {
  white-space: pre;
}
<input id="input" min=1 value=1 type=Number>
<div id="output"></div>

\$\endgroup\$
9
  • \$\begingroup\$ Which characters exactly must be eligible for appearing? \$\endgroup\$
    – xnor
    Jul 27, 2016 at 1:01
  • \$\begingroup\$ @xnor Characters from ! to ~ sans y and Y \$\endgroup\$ Jul 27, 2016 at 1:02
  • \$\begingroup\$ @LegionMammal978 No, because non-Y characters include y and . \$\endgroup\$
    – Leaky Nun
    Jul 27, 2016 at 1:05
  • 8
    \$\begingroup\$ Hmm.. random... \$\endgroup\$ Jul 27, 2016 at 2:26
  • 16
    \$\begingroup\$ Wait!? We're allowed to use "Y" and "y" in the our code? \$\endgroup\$
    – Adám
    Jul 27, 2016 at 5:35

28 Answers 28

10
\$\begingroup\$

Ruby, 102 bytes

Array#sample doesn't do repetitions for sampling from the character set, but that's OK because the character distribution don't have to be perfectly uniform! Recursive function, returns an array of lines.

Try it online!

f=->l{w,x,y,z=([*?!..?~]-%w"y Y").sample 4
l<2?[w]:[w+(s=' '*(l-2))+x,*f[l-2].map{|e|" #{e} "},y+s+z]}
\$\endgroup\$
1
  • \$\begingroup\$ Even without repetition, each character has equal chance to be picked =) It's just that you can't generate output that have repeated characters. \$\endgroup\$
    – justhalf
    May 19, 2021 at 9:21
7
\$\begingroup\$

Mathematica, 146 bytes

a:=RandomChoice[33~CharacterRange~126~Complement~{"Y","y"}];StringRiffle[Normal@SparseArray[{{b_, b_}:>a,{b_,c_}/;c-1==#-b:>a},{#,#}," "],"
",""]&

Anonymous function. Takes a number as input, and returns a string as output.

\$\endgroup\$
7
\$\begingroup\$

Actually, 62 bytes

"!⌂"♂┘ix♂c"Yy"@-╗½≈u;r2@∙`i=`M╪k`;dXR@+`M;dXR@+`"╜J' aI"£MΣ`Mi

This is one of the longest Actually programs I've ever written.

Try it online!

Explanation:

Part 1: setting up the character list

"!⌂"♂┘ix♂c"Yy"@-
"!⌂"              push the string "!⌂"
    ♂┘            CP437 ordinal of each character ([21, 127])
      ix          range(21, 127)
        ♂c        character at each ordinal (list of printable ASCII characters)
          "Yy"@-  set difference with ["Y", "y"] (printable ASCII except "Y" and "y")

Try it online!

Part 2: constructing the boolean array for an X

½≈u;r2@∙`i=`M╪k`;dXR@+`M;dXR@+
½≈u;                            two copies of int(input/2)+1
    r                           range
     2@∙                        Cartesian product with itself
        `i=`M                   for each sublist: push 1 if both elements are equal, else 0
             ╪k                 split into int(input/2)+1-length chunks
                                (at this point, we have one quarter of the X)
               `;dXR@+`M        mirror each sublist (one half of the X)
                        ;dXR@+  mirror the entire list (the whole X)

Try it online!

Part 3: picking random characters

`"╜J' aI"£MΣ`Mi
`"╜J' aI"£MΣ`M   for each row:
 "╜J' aI"£M        for each column:
  ╜J                 push a random value from the character list
    '                push a space
      a              invert the stack
       I             take the character if the value is 1, else take the space
           Σ       concatenate the strings
              i  flatten the list and let implicit output take care of the rest

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ "Visualize bit weaving" was 69 bytes ;-) \$\endgroup\$ Jul 27, 2016 at 12:36
7
\$\begingroup\$

Python, 142 139 135 bytes

This is a straight forward implementation create the square character by character. If the character is on a diagonal: use a random char, else: use a space. This also uses a regex substitution and random int to generate non-Y characters:

import re,random
lambda x:''.join('\n'*(i%x<1)+re.sub("y|Y","t",chr(random.randint(33,126))+' ')[i%x!=i/x!=x-i%x-1]for i in range(x*x))

Explanation [ Old ]

"\n".join( ... for i in range(x)) # Create 'x' lines 
''.join( ... for j in range(x))   # Create 'x' chars on each line
(...)[j!=i!=x-j-1]                # Not on diagonals? 2nd char in "? "; Else, choose the 1st
j!=i                              # Not on downward diagonal
i!=x-j-1                          # Not on upward diagonal
re.sub("y|Y","t", ... )           # Replace y or Y for t
chr(random.randint(33,126))+' '   # Random char + a space

Update

  • -4 [16-07-30] Shortened newline conditional
  • -3 [16-07-30] Changed to single for-loop
  • -6 [16-07-29] Exchanged if statement for ternary op. Thanks to @RootTwo
  • -11 [16-07-27] Removed extra brackets/spaces and flipped if statement
  • -49 [16-07-27] Absorded @squeamishossifrage's method by creating the square step-by-step, Thanks!
  • -10 [16-07-27] Shorten random char lambda + math stuff from @ConorO'Brien
  • -22 [16-07-26] Squeaze in a lambda + misc golfing
  • -6 [16-07-26] import* - Thanks to @KevinLau
\$\endgroup\$
4
  • 1
    \$\begingroup\$ randint is probably shorter for your purposes, plus from random import*. Also, remove some of that unnecessary white space. \$\endgroup\$
    – Value Ink
    Jul 27, 2016 at 2:55
  • 2
    \$\begingroup\$ [i,33][i in(89,121)] works instead needing a long-winded ternary in your f function! Also see if you can remove the space that's right after your print statements \$\endgroup\$
    – Value Ink
    Jul 27, 2016 at 4:08
  • \$\begingroup\$ I would suggest trying a different format for your code explanation. This isn't very readable. Try looking at how other users do theirs. Even this would be better. \$\endgroup\$
    – mbomb007
    Jul 28, 2016 at 21:55
  • 1
    \$\begingroup\$ re.sub("y|Y","t",chr(random.randint(33,126))+' ')[j!=i!=x-j-1] saves 6 bytes over the ... if ... else ... construct. \$\endgroup\$
    – RootTwo
    Jul 29, 2016 at 20:02
6
\$\begingroup\$

Python 2, 171 bytes

from random import*
def x(n):
 w=range(-n/2+1,n/2+1)
 for i in w:
  o=''
  for j in w:c=randint(33,124);c+=(c>88)+(c>119);c=[c,32][bool(i^j and i^-j)];o+=chr(c)
  print o

Guaranteed to choose random characters with uniform probability.

Try it out here: ideone link

EDIT: Thanks to Morgan Thrapp for the corrections.

\$\endgroup\$
5
  • \$\begingroup\$ from random import* saves 2 bytes. You can also join the first two lines of the j loop with a semicolon to save some bytes. (Also I believe Z and { have a higher chance of occurring than some other letters, not that it matters for the question) \$\endgroup\$ Jul 27, 2016 at 19:50
  • \$\begingroup\$ You can get down to 165 with a couple small modifications mothereff.in/… \$\endgroup\$ Jul 27, 2016 at 19:55
  • 2
    \$\begingroup\$ Actually, your output is wrong for all the test cases. You're making each leg equal to n instead of the total side size. \$\endgroup\$ Jul 27, 2016 at 20:00
  • \$\begingroup\$ @MorganThrapp Ah, you're right. I'll fix that \$\endgroup\$
    – r3mainer
    Jul 27, 2016 at 20:32
  • \$\begingroup\$ 4 bytes: bool(i^j and i^-j) -> i not in(j,-j) \$\endgroup\$ Aug 21, 2016 at 3:44
5
\$\begingroup\$

Dyalog APL, 35 bytes

⎕UCS 32+(⊢+∊∘57 89)⌊?95×(⊢∨⌽)∘.=⍨⍳⎕

prompt for number
1 through that number
∘.=⍨ equality table (i.e. the diagonal has 1s)
(⊢∨⌽) itself OR its mirror image (gives both diagonals)
95× multiply by 95
? rand int between 1 and 95 for the diagonals, rand float between 0 and 1 for the rest
floor to get rid of the floats
(⊢+∊∘57 89) add one to the elements that are a member of {57,89} (Yy – 32)
32+ add 32 to make the 0s into spaces, and other numbers into the proper range
⎕UCS convert to text

TryAPL!

\$\endgroup\$
2
  • \$\begingroup\$ I like how this one also reacts with even numbers, even though that wasn't part of the problem (and might even be unintentional). Good job! Though, oddly, it sometimes treats an input of 4 differently than any other input. \$\endgroup\$
    – kirkpatt
    Jul 27, 2016 at 16:23
  • \$\begingroup\$ @kirkpatt Yeah, I didn't even notice the "odd-only".. \$\endgroup\$
    – Adám
    Jul 27, 2016 at 16:24
4
\$\begingroup\$

Pyth, 28 27 26 25 bytes

jmuXGHO-rF"!~""Yy"{,d-tQd*;Q
VQuXGHO-rF"!~""Yy"{,N-tQN*d
VQuXGHO-r\!\~"Yy"{,N-tQN*d
VQuXGHO-r\!\~"Yy",N-tQN*d
VQuXGHO-r\!\[DEL];"Yy",N-tQN*d

Try it online!

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

x86 machine code, 70 bytes

60 89 d7 31 db 43 88 ce b2 fe 49 d1 e1 87 da 0f
c7 f0 24 7f 3c 22 72 f7 48 3c 79 74 f2 3c 59 74
ee aa 49 7c 1c 00 df 79 06 86 f7 42 43 eb f6 f6
c3 01 74 03 b0 0a aa 51 88 f9 b0 20 f3 aa 59 eb
cc c6 07 00 61 c3

My executable code, disassembled:

0000003d <myheh>:                                       
  3d:   60                      pusha                   
  3e:   89 d7                   mov    %edx,%edi        
  40:   31 db                   xor    %ebx,%ebx        
  42:   43                      inc    %ebx             
  43:   88 ce                   mov    %cl,%dh          
  45:   b2 fe                   mov    $0xfe,%dl        
  47:   49                      dec    %ecx             
  48:   d1 e1                   shl    %ecx             

0000004a <myloop>:                                      
  4a:   87 da                   xchg   %ebx,%edx        

0000004c <myrand>:                                      
  4c:   0f c7 f0                rdrand %eax             
  4f:   24 7f                   and    $0x7f,%al        
  51:   3c 22                   cmp    $0x22,%al        
  53:   72 f7                   jb     4c <myrand>      
  55:   48                      dec    %eax             
  56:   3c 79                   cmp    $0x79,%al        
  58:   74 f2                   je     4c <myrand>      
  5a:   3c 59                   cmp    $0x59,%al        
  5c:   74 ee                   je     4c <myrand>      
  5e:   aa                      stos   %al,%es:(%edi)   
  5f:   49                      dec    %ecx             
  60:   7c 1c                   jl     7e <mydone>      

00000062 <mylab>:                                       
  62:   00 df                   add    %bl,%bh          
  64:   79 06                   jns    6c <myprint>     
  66:   86 f7                   xchg   %dh,%bh          
  68:   42                      inc    %edx             
  69:   43                      inc    %ebx             
  6a:   eb f6                   jmp    62 <mylab>       

0000006c <myprint>:                                     
  6c:   f6 c3 01                test   $0x1,%bl         
  6f:   74 03                   je     74 <myprint1>    
  71:   b0 0a                   mov    $0xa,%al         
  73:   aa                      stos   %al,%es:(%edi)   

00000074 <myprint1>:                                    
  74:   51                      push   %ecx             
  75:   88 f9                   mov    %bh,%cl          
  77:   b0 20                   mov    $0x20,%al        
  79:   f3 aa                   rep stos %al,%es:(%edi) 
  7b:   59                      pop    %ecx             
  7c:   eb cc                   jmp    4a <myloop>      

0000007e <mydone>:                                      
  7e:   c6 07 00                movb   $0x0,(%edi)      
  81:   61                      popa                    
  82:   c3                      ret                     

It is a function that receives the size of the X in ecx, and a pointer to the output buffer in edx.

It fills the output buffer sequentially with bytes. There are 2 * n - 1 iterations (equal to the number of non-space characters to output). At each iteration, it does the following:

  • Generate a random number
  • Fiddle with the number to fit it into range; if it's bad, go back and generate anew
  • Print the random character
  • Print a newline (every other iteration)
  • Print the proper number of spaces

Conversion from a random number to a random character is not remarkable:

myrand:
    rdrand eax;
    and al, 7fh;
    cmp al, 22h;
    jb myrand;
    dec eax;
    cmp al, 'y';
    je myrand;
    cmp al, 'Y';
    je myrand;

The interesting part is the calculation of the number of spaces. It must generate the following numbers (example for N=9):

7    1
5    2
3    3
1    4

     3
1    2
3    1
5    0
7

The numbers are taken alternatingly from two arithmetic progressions. The first one goes down with step -2, and the second one goes up with step 1. When the first progression arrives at -1 (in the middle of the X), there is a glitch (-1 is removed), and then the progressions change direction.

The progressions are stored in registers ebx and edx - the high parts bh and dh store the current number, and the low parts bl and dl store the step. To alternate between the progressions, the code swaps the registers with xchg.

When the progression arrives at -1 (around the mylab label), it increases both registers, switching the steps from -2, 1 to -1, 2. This also changes the roles of the registers, so then it swaps the high parts of the registers.

At the end of the function, it stores a zero byte to indicate an end of string.

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

Python 2.7, 205 bytes:

from random import*;C=input()/2;S=' ';R=range;Z=lambda:chr(choice(R(33,89)+R(90,121)+R(122,128)));T=lambda*G:''.join([S*i+Z()+S*(2*(~-C-i)+1)+Z()+S*i+'\n'for i in R(*G)]);print T(C)+S*C+Z()+'\n'+T(~-C,-1,-1)

Try It Online! (Ideone)

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

MATL, 28 bytes

6Y2'Yy 'X-iZr1MZrXdwXdP2$X>c

Try it online!

All the allowed characters have the same probability of appearing. Works for even input too.

6Y2     % Predefined literal of ASCII chars from 32 to 126
'Yy '   % Not allowed chars
X-      % Set difference. Produces the set of allowed chars
i       % Input number, n
Zr      % Random sample without replacement. Gives a string with n chars taken from 
        % the allowed set
1MZr    % Do the same
Xd      % Diagonal matrix. Zeros will be displayed as spaces
wXd     % Diagonal matrix with the other string
P       % Flip vertically
2$X>    % Maximum of the two matrices
c       % Convert to char. Implicitly display
\$\endgroup\$
3
\$\begingroup\$

C, 154 bytes (or 119 without the boiler-plate)

o(w,c){c=rand()%94+33;printf("%*c",w,w?c+!(c&95^89):10);}main(h){scanf("%d",&h);srand(time(0));for(int n=h,p;n--;)p=abs(h/2-n),o(h/2-p+1),p&&o(p*2),o(0);}

Or 119 bytes as a function X(h) with srand(time(0)) taken care of elsewhere:

o(w,c){c=rand()%94+33;printf("%*c",w,w?c+!(c&95^89):10);}X(h,n,p){for(n=h;n--;)p=abs(h/2-n),o(h/2-p+1),p&&o(p*2),o(0);}

Breakdown:

o(w,c){                         // "Output" function, for all printing
    c=rand()%94+33;             // Generate random char, whether we need it or not
    printf("%*c",               // Print a char with some number of leading spaces
           w,                   // Use "w" (width) - 1 leading spaces
           w?                   // Either print the random char...
             c+!(c&95^89)       // (exclude "y" and "Y" by incrementing to "z"/"Z")
                         :10    // ...or print a newline if called with w = 0
    );
}
main(h){                        // Main function; repurpose argc to store grid size
    scanf("%d",&h);             // Get grid size from stdin
    srand(time(0));             // Boiler-plate for random number seeding
    for(int n=h,p;n--;)         // Loop over all lines (count down to save chars)
        p=abs(h/2-n),           // Calculate half-distance between "X" bars
        o(h/2-p+1),             // Output the first half of the "X" (">")
        p&&                     // If we are not in the centre:
           o(p*2),              //   output the second half of the "X" ("<")
        o(0);                   // Output a newline
}
\$\endgroup\$
2
\$\begingroup\$

Lua, 277 Bytes

Well... Lua is sooooo good at manipulating strings :D. First time I had to use local in a statement! I could save some bytes by using Lua 5.1 instead of 5.3 because they moved the global function unpack into the object table at Lua 5.2. But I prefer to stick with the latest version I have :).

Defines a function that should be called with a single parameter (the second one is used for recursion purpose) and returns a string.

function f(n,N)N=N or n e=" "p="\n"r=math.random C=e.char
R={}for i=1,4 do x=r(33,126)R[i]=x~=89 and x~=121 and x or r(33,88)end
local s,S,a,b,c,d=e:rep((N-n)/2),e:rep(n-2),table.unpack(R)return
n<2 and s..C(a)..p or s..C(a)..S..C(b)..s..p..f(n-2,N)..s..C(c)..S..C(d)..s..p
end

Ungolfed

function f(n,N)                       
  N=N or n                          -- N is equal to the n we had on the first call
  e=" "                             -- shorthand for the space
  p="\n"                            -- shorthand for the newline
  r=math.random                     -- shorthand for math.random
  C=e.char                          -- uses the string e to obtain the function string.char
  R={}                              -- define an array for our random values
  for i=1,4                         -- iterate 4 times (for the random characters)
  do
    x=r(33,126)                     -- random between ASCII "!" and "~"
    R[i]=x~=89 and x~=121           -- if we didn't pick y or Y
           and x                    -- keep this number
         or r(33,88)                -- or roll for a character between "!" and "X"
  end
  local s,S                         -- these variables have to be local
          ,a,b,c,d                  -- or the recursion would change them
         =e:rep((N-n)/2),e:rep(n-2) -- s and S are the number of spaces for the X
           ,table.unpack(R)         -- a,b,c and d are the 4 random characters
  return n<2                        -- if n==1 
           and s..C(a)..p           -- we're at the center of the X, time to end recursion
         or                         -- else
           s..C(a)..S..C(b)..s..p   -- concatenate the topmost line for n
           ..f(n-2,N)               -- with the inner X
           ..s..C(c)..S..C(d)..s..p -- and the bottom line
end
\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 137 131 125 bytes

n=>[...Array(n)].map((_,i,a)=>String.fromCharCode(...a.map((r=Math.random()*94,j)=>i-j&&i+j+1-n?32:(r+72&95&&r)+33))).join`\n`

Where \n represents the literal newline character. Edit: Saved 1 byte by moving the ' ' inside the String.fromCharCode expression. Saved 5 bytes by making my random character generation non-uniform; the expression r+72&95 is zero for the values that map to Y and y and an ! is generated in their place. Saved 4 bytes when I realised that spreading over String.fromCharCode avoids having to join. Saved 2 bytes by stealing a trick from @edc65.

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

PowerShell v2+, 112 bytes

Param($i)function f{Random(33..126-ne121-ne89|%{[char]$_})};1..$i|%{$a=,' '*$i;$a[$_-1]=f;$a[$i-$_]=f;$a-join''}

Reads input off the command line.

For each line, an array of spaces is created, the correct indices filled in with characters pulled from function f, then the char array is joined to output as one line.

\$\endgroup\$
4
  • \$\begingroup\$ You can save 6 bytes by moving the [char] cast outside of Random, and by flipping the -join to be a unary operator --- Param($i)function f{[char](Random(33..126-ne121-ne89))};1..$i|%{$a=,' '*$i;$a[$_-1]=f;$a[$i-$_]=f;-join$a} \$\endgroup\$ Aug 3, 2016 at 13:51
  • \$\begingroup\$ Actually, you can save another couple bytes by replacing the function with the PowerShell equivalent of a lambda and use the call-operator & to call it. The following is 103 bytes -- Param($i)$z={[char](Random(33..126-ne121-ne89))};1..$i|%{$a=,' '*$i;$a[$_-1]=&$z;$a[$i-$_]=&$z;-join$a} \$\endgroup\$ Aug 3, 2016 at 14:53
  • \$\begingroup\$ Actually, actually ;-), you can save some more by collapsing your -ne, moving the [char] cast to be a [char[]] cast on $a (swapping ' ' for 32 in the process), and moving $z's definition into a parens the first time it's called. Down to 99 (woo! sub-100!) -- Param($i)1..$i|%{$a=,32*$i;$a[$_-1]=&($z={Random(33..126-ne121,89)});$a[$i-$_]=&$z;-join[char[]]$a} \$\endgroup\$ Aug 3, 2016 at 15:07
  • \$\begingroup\$ Hah, save another byte by moving $a's definition into a parens the first time it's used. Down to 98 now -- Param($i)1..$i|%{($a=,32*$i)[$_-1]=&($z={Random(33..126-ne121,89)});$a[$i-$_]=&$z;-join[char[]]$a} I think I'll stop here ;-) hehe \$\endgroup\$ Aug 3, 2016 at 15:12
2
\$\begingroup\$

Matricks, 79 bytes (non-competing)

Matricks excels as the beginning of making the x and all the random values, but flops when it comes to conditionals...

I marked this as noncompeting because I had to fix a few bugs and get all the new features working after this challenge was posted.

m:n;:1;mr=c:L:L;k({}|{X;})*{m_?33:126;;:L:l;miC<121,89>:gr:c;;:49:gr:c;;:L:l;};

Run with python matricks.py x.txt [[]] <input> --asciiprint

Explanation:

m:n;:1;mr=c:L:L;                   #Initialize matrix to be a square with
                                   #a diagonal of 1s
k...;                              #Set the output to...
({}|{X;})*                         #The boolean x matrix multiplied by...
{m_?33:126;;:L:l;                  #A bunch of random characters
miC<121,89>:gr:c;;:49:gr:c;;:L:l;} #But make sure they are not y or Y

This also supports even numbers.

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

MATLAB, 86 bytes

a=@(n)(char(changem(randi(92,n),33+[0:55 57:87 89:93],1:92).*(eye(n)|fliplr(eye(n)))))

Some examples:

>> a(1)

ans =

i


>> a(3)

ans =

~ {
 Z 
* ^


>>a(5)

ans =

k   E
 | M 
  }  
 ] s 
b   t


>> a(10)

ans =

Q        k
 +      a 
  j    w  
   X  [   
    rO    
    %3    
   P  d   
  K    q  
 r      & 
?        v
\$\endgroup\$
1
  • \$\begingroup\$ So, a function that changes values in a matrix according to some rules is called changem! Great name! \$\endgroup\$
    – anatolyg
    Jul 29, 2016 at 9:18
2
\$\begingroup\$

SmileBASIC, 97 bytes

INPUT S
FOR X=1TO S
FOR Y=1TO S
Q=RND(93)+33?CHR$((Q+!(Q-121&&Q-89))*(X==Y||X+Y==S+1));
NEXT?NEXT

Instead of having to calculate the number of spaces between each character or something, I decided to just print in all locations where X==Y or X+Y==Size+1.
The random character generator just adds 1 if it generates y or Y, so z and Z are slightly more common than usual.

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

Pip, 33 bytes

32 bytes of code, +1 for -l flag. Strangely enough, the code begins with Y and ends with y...

Ya{$=a|$+a=y-1?RCPARM-`y`s}MMCGy

Takes input as a command-line argument. Try it online!

Explanation

Constructs a grid of the appropriate size; replaces elements on the diagonals with a random non-y character, and all other elements with space.

                                  a is 1st cmdline arg; PA is printable ASCII characters;
                                  s is space (implicit)
Ya                                Yank a into y (global var, accessible within functions)
                             CGy  y by y coordinate grid
  {                       }MM     To each coordinate pair, map this function:
   $=a                             Fold on equality (true if both elements are equal)
      |                            Logical OR
       $+a                         Fold on +
          =y-1                     and test if equal to size - 1
              ?                    If the preceding expression is true, then:
                 PARM               From printable ASCII chars, remove         
                     -`y`           regex matching y, case-insensitive
               RC                   Take a random choice from the resulting string
                         s         Else, space
                                  The whole expression returns a nested list, which is
                                  autoprinted as lines of concatenated items (-l flag)
\$\endgroup\$
2
\$\begingroup\$

Japt -R, 25 22 bytes

A much messier approach that somehow worked out shorter than the original. The need for the j1 is annoying me but this is the closest I can get otherwise, without tanking my score (the middle line is wrong).

;Æ2ÆEÅkÕöÃqSp´UaX¹j1Ãû

Try it

;Æ2ÆEÅkÕöÃqSp´UaX¹j1Ãû     :Implicit input of integer U
 Æ                         :Map each X in the range [0,U)
  2Æ                       :  Map the range [0,2)
;   E                      :    ASCII
     Å                     :    Slice off the first character (space)
      k                    :    Case insensitively remove
       Õ                   :      "y"
        ö                  :    Random character
         Ã                 :  End map
          q                :  Join with
           S               :    Space
            p              :    Repeat
             ´U            :      Prefix decrement U
               aX          :      Absolute difference with X
                 ¹         :  End join
                  j1       :  Remove character at 0-based index 1
                    Ã      :End map
                     û     :Centre pad each element with spaces to the length of the longest
                           :Implicit output joined with newlines

Original (w/o flag), 25 bytes

;z ôÈç iÕêÃÔê û ·ry@EÅkÕö

Try it

;z ôÈç iÕêÃÔê û ·ry@EÅkÕö     :Implicit input of integer
 z                            :Floor divide by 2
   ô                          :Range [0,result]
    È                         :Map each X
     ç                        :  X spaces
       i                      :  Prepend
        Õ                     :    "y"
         ê                    :  Palindromise
          Ã                   :End map
           Ô                  :Reverse
            ê                 :Palindromise
              û               :Centre pad each element with spaces to the length of the longest
                ·             :Join with newlines
                 ry           :Replace "y"s
                   @          :  Pass each match through the following function
;                   EÅkÕö     :    As above
\$\endgroup\$
2
\$\begingroup\$

Zsh, 115 122 130 bytes

for i ({1..$1}){for j ({1..$1}){x=$[(i==j)|(j+i==$1+1)?RANDOM%93+33:32]
echo -n ${${(#)x==45?89:x}/[yY]/\-}};echo}
  • i & j iterate over the rows & columns.
  • If we're on the X, set x to to a random ascii-value in the valid range, otherwise 32 [space].
  • Convert ascii-value to text. Switch "-" character (45) to a "Y" (89) if found (necessary to avoid a bug). Change "y" or "Y" to hyphen char "-", and print

try it online!   122 bytes 130 bytes

\$\endgroup\$
2
  • \$\begingroup\$ We don't allow the input to be assigned to a predefined variable. \$\endgroup\$
    – Shaggy
    Aug 18, 2021 at 11:47
  • \$\begingroup\$ Fixed. But the challenge states "given an odd integer n..." \$\endgroup\$
    – roblogic
    Aug 18, 2021 at 18:34
1
\$\begingroup\$

php, 135 bytes

<?php for(;$i<$n=$argv[1];){$s=str_pad('',$n);$s[$i?:0]=chr(rand(33,126));$s[$n-++$i]=chr(rand(33,126));echo str_ireplace(Y,X,"$s
");}

Fairly straightforward approach uses str_pad to make a string of spaces of the required length, replaces the necessary characters with random ones then replaces any Ys (case insensitive) with Xs and echos the line.
Generates 2n+3 notices but, as usual, that's fine.

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

Emacs Lisp, 269 bytes

(defalias'n'number-sequence)(set'c(mapcar'string(delq 89(delq 121(n 33 126)))))(defun c()(nth(random(length c))c))(defun s(x)" ")(defun x(l)(let((s(mapcar's(n 1 l))))(dotimes(i l)(set'x(copy-seq s))(setf(nth i x)(c)(nth(-(length x)i 1)x)(c))(message(apply'concat x)))))

Ungolfed and slightly modified:

(defvar c (mapcar 'string (delq 89 (delq 121 (number-sequence 33 126)))))
(defun c() (nth (random (length c)) c))
(defun s(x)" ")
(defun x(l)
  (let ((s(mapcar's(n 1 l)))
        x)
    (dotimes (i l)
      (set 'x (copy-seq s))
      (setf (nth i x) (c)
            (nth (- (length x) i 1) x) (c))
      (message (apply 'concat x)))))
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 128 131

Edit 3 bytes saved thx @Neil

So bulky, probably not the best approach. Bonus - it works with odd or even input.

n=>[...Array(n)].map((_,i,z)=>String.fromCharCode(...z.map((r=1+Math.random()*94,j)=>32+(j==i|j==n+~i&&(r+7&31?r:25))))).join`
`

F=n=>[...Array(n)].map((_,i,z)=>String.fromCharCode(...z.map((r=1+Math.random()*94,j)=>32+(j==i|j==n+~i&&(r+7&31?r:25))))).join`\n`

Z=_=>{
    o=F(+S.value),O.textContent=o,/y/i.test(o)||setTimeout(Z,100)
}
setTimeout(Z,100)
<input id=S value=15 type=number>
<pre id=O></pre>

\$\endgroup\$
3
  • \$\begingroup\$ I think r+7&31 gives the same result as (r&31)-25. \$\endgroup\$
    – Neil
    Jul 27, 2016 at 10:31
  • \$\begingroup\$ @Neil sounds good, thanks \$\endgroup\$
    – edc65
    Jul 27, 2016 at 13:23
  • \$\begingroup\$ I like how this illustrates the fact that it is random! +1 \$\endgroup\$ Jul 27, 2016 at 20:04
1
\$\begingroup\$

C, 268 bytes

V(c){for(c=89;c==89||c==121;c=rand()%95+33);return c;}p(n,s){n^1?s-n?printf("%*.c",s-n,32):0,printf("%c%*.c%c\n",V(),n*2-3,32,V()),p(n-1,s),s-n?printf("%*.c",s-n,32):0,printf("%c%*.c%c\n",V(),2*n-3,32,V()):printf("%*.c%c\n",s-n,32,V());}f(n){srand(time(NULL));p(n,n);}

Call f() with the size of the x to draw.

\$\endgroup\$
3
  • \$\begingroup\$ You have to call srand inside your functions, they cannot rely on global state. You can, however, achieve a much shorter program with two nested loops and using the backspace character. A general solution might look like this, but I think a windows specific variant using clock would be valid. \$\endgroup\$ Jul 27, 2016 at 18:26
  • \$\begingroup\$ Can you lease add the version of your compiler? on gcc version 4.8.1 for Windows and gcc version 5.3.0 for Cygwin it doesn't works... (on IdeOne Works ) \$\endgroup\$ Jul 28, 2016 at 9:41
  • \$\begingroup\$ I know it works with GCC 6.1.0, but it should at least work with >4.9. It also works with clang 3.8.1. What errors do you see? \$\endgroup\$
    – owacoder
    Jul 28, 2016 at 12:49
1
\$\begingroup\$

Python 2, 204 191 183 bytes

Okay, Python competition here is getting fierce. Here's my attempt on shaving as many bytes as possible. By now I'm stuck (Ok, stuck again).

Credits to @NonlinearFruit for the way random characters are selected.

183 byte version:

import re,random
s=i=input();t=lambda:re.sub("y|Y","t",chr(random.randint(33,126)))
while i>-s:i-=2;u=abs(i);z=(s-u)/2-1;print('',' '*-~z+t()+'\n')[-1==i]+(' '*z+t()+' '*u+t())*(i>-s)

Try It Online! (Ideone)

Main change is to rewrite the conditional

(" "*(z+1)+t()+"\n"if -1==i else"") 

as

(""," "*-~z+t()+'\n')[-1==i]

which saves 7 bytes.

191 byte version:

import re,random
s=i=input();t=lambda:re.sub("y|Y","t",chr(random.randint(33,126)))
while i>-s:
 i-=2;u=abs(i);z=(s-u)/2-1;print(' '*(z+1)+t()+'\n'if -1==i else'')+(' '*z+t()+' '*u+t())*(i>-s)

Try It Online! (Ideone)

Main changes are the way random characters are selected and some code rearrangement such as s=input();i=s; becoming s=i=input();, removing the r=range assignment as it is no longer needed and calling abs directly as it results in less bytes of code.

Beating the previous shortest answer in Python by 1 byte! @R. Kap 's approach is used for generating the random characters. Each iteration of the while loop a row of the ex is printed.

204 byte version:

from random import*
s=input();i=s;a=abs;r=range;t=lambda:chr(choice(r(33,89)+r(90,121)+r(122,128)))
while i>-s:
 i-=2;z=(s-a(i))/2-1;print(' '*(z+1)+t()+'\n'if -1==i else'')+(' '*z+t()+' '*a(i)+t())*(i>-s)

Try It Online! (Ideone)

Ungolfed version to get an idea of how it works:

from random import *
random_character = lambda : chr(choice(range(33,89)+range(90,121)+range(122,128)))

size = input()
current_row = size

while current_row > -size:
    current_row-=2
    n_leading_spaces = (size-abs(current_row)/2)-1 
    row_to_print = ''
    if current_row == -1:
        row_to_print = ' ' * (n_leading_spaces+1) + random_chr() + '\n'
    if current_row > -size:
        row_to_print += ' ' * n_leading_spaces + random_chr()+' '*abs(current_row)+random_chr()
    print row_to_print

It was hard to handle the 1-character case!

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

PHP, 100 bytes

for(;($x%=$n=$argv[1])?:$y++<$n&print"\n";)echo strtr(chr($y+$x++-$n&&$x-$y?32:rand(33,126)),yY,zZ);

takes input from command line argument; run with -nr.

combined loop prints characters depending on position

breakdown

for(;
    ($x%=$n=$argv[1])       // inner loop
        ?
        :$y++<$n&print"\n"  // outer loop; print newline
;)
    echo strtr(chr(             // 2. replace Y with Z; print
        $y+$x++-$n&&$x-$y       // 1: if position is not on diagonals
            ?32                 // then space
            :rand(33,126)       // else random printable
    ),yY,zZ);
\$\endgroup\$
1
\$\begingroup\$

Vyxal mM, 34 bytes

‹½ƛ\%꘍⁰↲øm;øm⁋?‹4*›ƛ‛yY95ɾ31+CF℅;%

Try it Online!

‹½ƛ       ;                        # Map 0...(n-1)/2...
   \%꘍                             # That many spaces before a %
      ⁰↲                           # Left-padded to correct width
        øm                         # Palindromise
           øm                      # Palindromise
             ⁋                     # Join by newlines
              ?‹4*›                # 4(n-1)+1
                   ƛ            ;  # Map 0...n...
                       95ɾ31+C     # Printable ASCII
                    ‛yY            # Push ys
                              F    # Remove ys
                               ℅   # Choose a random element from this
                                 % # Format the cross by this
\$\endgroup\$
0
1
\$\begingroup\$

Vyxal 2.6, 22 bytes

½⌈:ʁ\%꘍↲∞v∞⁋?dkP‛yYFƈ%

Try it Online!

½⌈:                    # Push ⌈x/2⌉ twice
   ʁ                   # For each 0...^-1
    \%꘍                # Prepend that many spaces to a %
½⌈     ↲               # Pad to length ⌈x/2⌉ with spaces
        ∞v∞            # Quad palindromise
           ⁋           # Join by newlines
                    ƈ  # Choose...
            ?d         # Input * 2
                    ƈ  # Random items from...
              kP       # Printable ASCII
                ‛yYF   # Without Y
                     % # Replace % in the first bit with the random chars
\$\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.