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

24 Answers 24

3
\$\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

Test suite.

\$\endgroup\$
  • 5
    \$\begingroup\$ I'm pretty sure this will never produce the ~ character, because the range doesn't include it. You can fix this by changing the ~ in the code to the literal DEL character. \$\endgroup\$ – FryAmTheEggman Jul 27 '16 at 13:03
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\$
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
    \$\begingroup\$ "Visualize bit weaving" was 69 bytes ;-) \$\endgroup\$ – AdmBorkBork Jul 27 '16 at 12:36
6
\$\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\$
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\$
  • \$\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\$ – FryAmTheEggman Jul 27 '16 at 19:50
  • \$\begingroup\$ You can get down to 165 with a couple small modifications mothereff.in/… \$\endgroup\$ – Morgan Thrapp Jul 27 '16 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\$ – Morgan Thrapp Jul 27 '16 at 20:00
  • \$\begingroup\$ @MorganThrapp Ah, you're right. I'll fix that \$\endgroup\$ – squeamish ossifrage Jul 27 '16 at 20:32
  • \$\begingroup\$ 4 bytes: bool(i^j and i^-j) -> i not in(j,-j) \$\endgroup\$ – Jonathan Allan Aug 21 '16 at 3:44
6
\$\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\$
  • 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 '16 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 '16 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 '16 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 '16 at 20:02
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\$
  • \$\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 '16 at 16:23
  • \$\begingroup\$ @kirkpatt Yeah, I didn't even notice the "odd-only".. \$\endgroup\$ – Adám Jul 27 '16 at 16:24
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\$
3
\$\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\$
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\$
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\$
  • \$\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\$ – AdmBorkBork Aug 3 '16 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\$ – AdmBorkBork Aug 3 '16 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\$ – AdmBorkBork Aug 3 '16 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\$ – AdmBorkBork Aug 3 '16 at 15:12
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\$
  • \$\begingroup\$ So, a function that changes values in a matrix according to some rules is called changem! Great name! \$\endgroup\$ – anatolyg Jul 29 '16 at 9:18
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\$
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\$
  • \$\begingroup\$ I think r+7&31 gives the same result as (r&31)-25. \$\endgroup\$ – Neil Jul 27 '16 at 10:31
  • \$\begingroup\$ @Neil sounds good, thanks \$\endgroup\$ – edc65 Jul 27 '16 at 13:23
  • \$\begingroup\$ I like how this illustrates the fact that it is random! +1 \$\endgroup\$ – Conor O'Brien Jul 27 '16 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\$
  • \$\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\$ – FryAmTheEggman Jul 27 '16 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\$ – Giacomo Garabello Jul 28 '16 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 '16 at 12:49
1
\$\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\$
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\$

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\$
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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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