Make a haystack (with a needle)

27

2

(Essentially the inverse of Find the needle in the haystack)

Given two tuples, (w, h) and (x, y), generate a haystack composed of a single random printable ASCII character of w width and h height with a needle made of a different random printable ASCII character at (x, y) when measured from the upper-left.

For example, when given (5,4) for the width and height, and (3,1) (zero-indexed) for the location of the needle, a possible haystack could be the following:

#####
###N#
#####
#####

Another possibility could be

*****
***$*
*****
*****

among hundreds of others.

Rules and Clarifications

  • Input and output can be given by any convenient method. This means you can take input as a list of list of integers, as a single string, as two integers via command-line and a tuple via function argument, etc.
  • You can print the result to STDOUT or return it as a function result.
  • Either a full program or a function are acceptable.
  • You can choose whether the (x, y) tuple is zero-indexed or one-indexed, but please specify in your solution which you're using.
  • You do not get to pick which characters to use. That's part of the challenge - randomly selecting the characters.
  • Every possible output for a given input must have a non-zero chance of appearing, but the randomness doesn't need to be uniform.
  • The haystack is guaranteed to be at least 2x2 in size, so it's unambiguous which is the needle and which is the hay.
  • There is only ever one needle, and it's only ever one character in size, and it's guaranteed to be within the boundaries of the haystack.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

AdmBorkBork

Posted 2019-10-16T14:36:41.177

Reputation: 41 581

Can we return a flat list of characters? – TFeld – 2019-10-16T15:02:13.737

@TFeld No, you must have \n (or equivalent) included where appropriate. – AdmBorkBork – 2019-10-16T15:05:16.540

can we return a matrix of characters? – dzaima – 2019-10-16T15:09:54.043

@dzaima But of course. – AdmBorkBork – 2019-10-16T15:11:04.077

4Obligatory xkcd about the choice of the characters. Applies to a few early answers... :p – Arnauld – 2019-10-16T15:34:54.303

2@Arnauld I don't know what was the magic here, but I completely read the challenge as I can use any ASCII printable characters "that I like", instead of "random", and it is funny another person also did same exact thing! I didn't mean to implement the random in such a beautiful way :P – Night2 – 2019-10-16T16:17:03.273

Can the order of elements in the tuples be altered, and can the input format be mangled in any other ways? – Unrelated String – 2019-10-17T07:15:37.910

1@UnrelatedString Yes and yes? Those are standard I/O rules. – AdmBorkBork – 2019-10-17T12:23:21.263

Just a quick question for clarity - the two random printable ASCII characters should be by definition, dissimilar, correct? – Taylor Scott – 2019-11-16T18:37:30.143

1@TaylorScott Yes, that's covered in the opening paragraph. The two characters need to be different. – AdmBorkBork – 2019-11-18T13:34:18.380

@AdmBorkBork- Thanks for the clarification, I can be completely blind sometimes and did not see that! Cheers – Taylor Scott – 2019-11-18T17:28:02.690

Answers

12

JavaScript (Node.js),  122 120 106  103 bytes

Recursively builds the output character by character. The coordinates are 0-indexed.

(w,h,x,y)=>(s=new Date%9023,g=X=>Y<h?Buffer([X-w?(x-X|y-Y?s+1:s%96)%95+32:13])+g(X<w?X+1:!++Y):'')(Y=0)

Try it online!

How?

Problem

To generate the haystack and the needle, we could either:

  • generate a random haystack and process some loop to generate a random needle until it's different from the haystack
  • shuffle the whole range of printable characters and pick the first 2 of them

Unfortunately, both approaches are rather lengthy in JS.

Solution

We use instead a method that guarantees to generate 2 distinct characters with a single random number and without any loop.

We pick a random seed \$s\$ in \$[0..9022]\$ and define the haystack \$h\$ and needle \$n\$ as:

$$\begin{align}&h=(s+1)\bmod 95\\ &n=(s\bmod 96)\bmod 95\end{align}$$

(we then need to add \$32\$ to turn them into printable ASCII codes)

Basically, \$h\$ follows the pattern:

$$1,2,3,...,94,0,1,2,3,...$$

while \$n\$ follows the pattern:

$$0,1,2,3,...,94,\color{red}0,0,1,2,3,...$$

The sequences are progressively shifted relative to each other because of the extra \$0\$ in the needle pattern.

This code shows that it does eventually lead to all possible pairs \$(h,n)\$ with \$h\neq n\$ (there are \$95\times 94=8930\$ of them).

And because we need only one random number, we can afford to use the current timestamp in milliseconds as our entropy source with new Date%9023 instead of the longer Math.random()*9023.

Commented

(w, h, x, y) => (      // w = width, h = height, (x, y) = coordinates
  s = new Date % 9023, // s = random seed in [0..9022]
  g = X =>             // g = recursive function taking X
    Y < h ?            //   if we've not reached the end of the grid:
      Buffer([         //     append the next character:
        X - w ?        //       if we haven't reached the end of the line:
          ( x - X |    //         if this is not the position of the needle:
            y - Y ?    //
              s + 1    //           append the haystack character
            :          //         else:
              s % 96   //           append the needle character
          ) % 95 + 32  //
        :              //       else:
          13           //         append a linefeed
      ]) +             //
      g(X < w ? X + 1  //     append the result of a recursive call
              : !++Y)  //     with either (X+1, Y) or (0, Y+1)
    :                  //   else:
      ''               //     stop recursion
)(Y = 0)               // initial call to g with X = Y = 0

Arnauld

Posted 2019-10-16T14:36:41.177

Reputation: 111 334

1Never seen new Date be used to generate a random seed before. Cool. – Daniel Vestøl – 2019-10-17T12:00:17.257

2@DanielVestøl, it's a common tactic in challenges where "random" is un(der)specified. – Shaggy – 2019-10-17T23:30:59.307

6

Jelly, 14 13 bytes

p/⁼€ịØṖẊ¤s⁸Ḣ¤

Try it online!

-1 byte thanks to Unrelated String

Returns a list of lines. The last line in the Footer section displays it as a square. Takes input as [w, h] and [y, x], where x and y are 0-indexed.

How it works

p/⁼€ịØṖẊ¤s⁸Ḣ¤ - Main link. Takes [w, h] on the left and [y, x] on the right
p/            - Reduce Cartesian product over the arguments.
                This yields a list of co-ordinates from (1, 1) to (h, w)
   €          - Over each list:
  ⁼           -   Is it equal to [x, y]?
              - This yields a list where every element except 1 is 0
        ¤     - Create a nilad:
     ØṖ       -   Printable ASCII characters
       Ẋ      -   Shuffled
    ị         - Index into the shuffled characters, replacing 1 with the first char in the shuffled list and 0 with the last. Therefore, the two characters will be distinct
            ¤ - Create a nilad:
          ⁸   -   Yield [w, h]
           Ḣ  -   Extract w
        s     - Split the list of characters into rows of length w
              - Implicitly output

caird coinheringaahing

Posted 2019-10-16T14:36:41.177

Reputation: 13 702

1-1 byte if you take [y, x] instead of [x, y] so you can drop the U – Unrelated String – 2019-10-17T12:29:01.327

1@UnrelatedString Huh, weird. That didn't work for me when I first posted it, but is now. Thanks! – caird coinheringaahing – 2019-10-17T12:34:41.383

6

Excel VBA, 128 118 106 94 96 bytes

-12 bytes inspired by agtoever
-12 bytes thanks to Taylor Scott, VBA extraordinaire
+2 bytes and -1 bug thanks to Taylor's unnecessary, intimidating, and much appreciated work

Sub n(w,h,x,y)
a=94*Rnd
[A1].Resize(h,w)=Chr(a+32)
Cells(y,x)=Chr(32+(a+93*Rnd+1)Mod 95)
End Sub

Input and output are one-indexed. Output is to the top left cell range of the active sheet.

a=94*Rnd+32: (126-32)*Rnd+32 gives a number between 32 and 126, inclusive.

Range(~)=Chr(a): Fills all the cells with the ASCII character.

Cells(y,x)=Chr(~): Fills just that one cell with the other ASCII character.

(a+62*Rnd)Mod 95+32: {(a+[94-32]*Rnd) Mod (126-32+1)}+32 gives a random number between 32 and 126 inclusive that is not the same as a. (I can't prove that mathematically but 100 million tests showed no collisions.)

Example output:

enter image description here

Engineer Toast

Posted 2019-10-16T14:36:41.177

Reputation: 5 769

Shorter: b=Chr(Asc(a)+1+95*Rnd Mod 127) instead of the do-while loop. – agtoever – 2019-10-20T06:53:34.520

Oh. And then you can just insert that statement in Cells(y,x)=... instead of assigning it to b. – agtoever – 2019-10-20T06:55:19.937

@agtoever I tested that. It results character codes up to 221 which is not allowed. I can't figure out how to modify it to generate a uniquely random integer 32-126. I kept hitting a ≈1.5% match rate, which is no good. However, that helped me find an error in my original code since it allowed up to 127 instead of 126. (It turns out that Chr() rounds instead of truncating.)

– Engineer Toast – 2019-10-21T13:48:22.833

Ow. Adding (+) has a lower operator precedence than Mod. Add parenthesis: Cells(y,x)=Chr((Asc(a)+1+94*Rnd)Mod127)) (not tested, maybe spaces are mandatory around Mod...)

– agtoever – 2019-10-22T08:06:57.547

1@agtoever I tried that when I was trying to get the previous suggestion to work. As written, b ends up in the range 0-126 instead of 32-126 although it's always unique from a. I massaged it a bit to get the most recent edit, which had 0% failure rate over 100 million runs. – Engineer Toast – 2019-10-22T14:17:25.533

1You can get down to 94 bytes if you use [A1].Resize(h,w)=Chr(a) – Taylor Scott – 2019-11-14T22:36:04.303

1

The 62 in the needle declaration didn't quite sit well with me, so I went and checked the math - it looks like as written it does avoid all possible collisions of a and b, but, it also fails to give 31 expected b values for every a value. I did work out a solution to this should only cost you two bytes - a=94*Rnd, Chr(a+32) and Chr(32+(a+93*Rnd+1)Mod 95) should give you everything you need. Uh, I've also been working on my own commenting and formatting habits, so here is a needlessly well commented proof of the above. Cheers!

– Taylor Scott – 2019-11-16T23:47:58.513

5

Python 2, 134 133 120 112 111 bytes

lambda w,h,x,y:zip(*[iter(chr(r[x+y*w==i]+32)for i in range(w*h))]*w)
from random import*
r=sample(range(95),2)

Try it online!

TFeld

Posted 2019-10-16T14:36:41.177

Reputation: 19 246

5

PowerShell v6, 102 96 bytes

param($x,$y,$a,$b)$j,$k=' '..'~'|random -C 2
-join((,$j*$x+++'
')*$y|%{"$_$k"[$i++-eq$b*$x+$a]})

Try it online!

This answer, thanks to mazzy, uses the character range feature added in v6 to save several bytes over the more flexible answer below.

PowerShell, 119..105 102 bytes

-16 bytes thanks to mazzy
-1 byte thanks to AdmBorkBork

param($x,$y,$a,$b)$j,$k=32..126|random -C 2
-join((,$j*$x+++'
')*$y|%{[char]($_,$k)[$i++-eq$b*$x+$a]})

Try it online!

Gets two ints in the range of [32,126]. We first make a 1D array out of the first value, appending a new line after every $xchars. Doing this means we also have to increment $x so that our index math isn't affected. We then iterate through the array, and either yield a char-ified first value or the needle. Finally, we join all the yielded values and output it.

Answer is 0-indexed by the way.

Veskah

Posted 2019-10-16T14:36:41.177

Reputation: 3 580

5

Jelly, 11 bytes

QŒṬƤSḂịØṖẊ¤

A monadic Link accepting a list of lists, [[height, width], [row, column]] (1-indexed), which yields a list of lists of characters.

Try it online! (The footer calls the link and joins with newlines.)

How?

QŒṬƤSḂịØṖẊ¤ - Link: [[h, w], [r, c]]
Q           - de-duplicate (i.e. [[h, w]] if [r, c] == [h, w] else [[h, w], [r, c]])
   Ƥ        - for prefixes (of that list):
 ŒṬ         -   get a 2D array with ones at the coordinates specified
    S       - sum (vectorises) (giving us an h*w matrix with zeros almost everywhere,
                                except a 1 at our needle and, if [h, w] != [r,c], a 2 at
                                the bottom-right)
     Ḃ      - modulo two (replacing the 2 with a zero if it exists)
          ¤ - nilad followed by link(s) as a nilad:
       ØṖ   -   list of printable characters
         Ẋ  -   shuffled
      ị     - (left) index into (right) (vectorises)

Jonathan Allan

Posted 2019-10-16T14:36:41.177

Reputation: 67 804

4

Dyalog APL, 24 23 21 bytes

⎕UCS(32+2?95)[⎕∘≡¨⍳⎕]

Try it online! 0-indexed.

-1 thanks to ngn, -2 thanks to Adám suggesting to use a different I/O format.

dzaima

Posted 2019-10-16T14:36:41.177

Reputation: 19 048

(⎕UCS 32+2?95) -> ⎕UCS(32+2?95) – ngn – 2019-10-16T15:26:37.580

⎕UCS(32+2?95)[⎕∘≡¨⍳⎕] – Adám – 2019-10-17T11:48:51.317

4

Python 2, 133 bytes

from random import*
r=range
def f(h,w,x,y):
 p=sample(r(32,127),2)
 for i in r(h):
	print ''.join(chr(p[i==y and j==x])for j in r(w))

Try it online!

-12 thanks to Value Ink for suggesting using a loop comprehension. -2 thanks to Unrelated String for suggesting python 2 instead of python 3 to get rid of parenthesis in the print function!

Benguini

Posted 2019-10-16T14:36:41.177

Reputation: 81

4

Welcome to PPCG! My first thought was to wrap the innermost loop into a loop comprehension that is then joined together and printed, to eliminate both the end='' part as well as the additional print() call after the loop. This cut the size down to 135 bytes. Try it online!

– Value Ink – 2019-10-17T00:50:27.697

You can also shave two more off by using Python 2 instead of 3, but it's minor.

– Unrelated String – 2019-10-17T06:47:05.093

print(end=chr(p[i==y and j==x])) saves three bytes – Black Owl Kai – 2019-10-18T06:38:49.180

3

Python 2, 110 bytes

from random import*
w,h,x,y=input()
m,n=sample(map(chr,range(32,127)),2)
l=eval(`[[m]*w]*h`)
l[x][y]=n
print l

Try it online!

I copied TFeld's solution and managed to golf a char using list assignment. The eval() trick is used to make a mutable matrix to avoid the list mutation applying to every row.

111 bytes

lambda w,h,x,y:[[chr(r[x^i<1>y^j]+32)for i in R(w)]for j in R(h)]
from random import*
R=range
r=sample(R(95),2)

Try it online!

A smaller change that only tied. Calling the function multiple times always give the same random choices, which I hope is OK.

109 bytes

lambda w,h,x,y:[m*w]*y+[m*x+n+m*(w+~x)]+[m*w]*(h+~y)
from random import*
m,n=sample(map(chr,range(32,127)),2)

Try it online!

A shorter function making the list of lines via multiplication. Also generates the characters just once.

xnor

Posted 2019-10-16T14:36:41.177

Reputation: 115 687

Nice! I didn't know about that eval trick. – quintopia – 2019-10-31T01:19:17.110

2

Perl 5, 86 bytes

($,,$b)=keys%{{map{chr,1}33..126}};$_=($,x$F[0].$/)x$F[1];s;(.*
){$F[3]}.{$F[2]}\K.;$b

Try it online!

Nahuel Fouilleul

Posted 2019-10-16T14:36:41.177

Reputation: 5 582

2

Julia 1.0, 71 bytes

f(w,h,x,y)=(z=unique(rand(' ':'~',9));g=fill(z[1],(h,w));g[y,x]=z[2];g)

x,y are one indexed. Returns a 2d array of characters, I spent the extra bytes to make sure the default printing has the right orientation (' for transpose no longer works because they stick to a strict mathematical meaning). Getting two distinct randoms is surprisingly verbose, this has about a 1e-18 chance of failing to do so, one more byte could make it 1e-196.

Try it online!

gggg

Posted 2019-10-16T14:36:41.177

Reputation: 1 715

2

J, 21 bytes

u:@(32+2?95){~#.=i.@[

Try it online!

Inspired by dzaima's APL answer.

Thanks to Galen and Adam for the randomize fix.

Jonah

Posted 2019-10-16T14:36:41.177

Reputation: 8 729

Fix by Adam – Galen Ivanov – 2019-10-16T16:15:33.183

You need two tuples as input – Galen Ivanov – 2019-10-16T16:18:41.567

Yeah I just noticed that, will fix. Thanks for the other fix btw. – Jonah – 2019-10-16T16:19:04.687

2

Octave with Statistics Package, 45 bytes

@(x)randsample(' ':'~',2)(sparse(x{:},0:1)+1)

The input is a cell array of 2 numeric vectors of length 2: {[h y] [w x]}, with x,y 1-based.

Try it online!

Luis Mendo

Posted 2019-10-16T14:36:41.177

Reputation: 87 464

2

Ruby, 62 bytes

->w,h,x,y{a,b=[*?\s..?~].sample 2;r=[a*w]*h*$/;r[y*-~w+x]=b;r}

Try it online!

Value Ink

Posted 2019-10-16T14:36:41.177

Reputation: 10 608

2

Excel + CSV, 104 bytes

,,,,=94*RAND()+32,=REPLACE(REPT(REPT(CHAR(E1),A1)&"
",B1),D1*A1+D1+C1+1,1,CHAR(MOD(E1+62*RAND(),95)+32))

Save as CSV, add input as A1 - D1. Output will be in F1.

Using @Engineer Toast's solutoin for generating 2 unique characters.

Needle position is 0-indexed, which is curious, as Excel itself if 1-indexed. Changing to 1-indexed input adds 3 bytes ((D2-1)*(A2+1)+C2 instead of D1*A1+D1+C1+1).

Wernisch

Posted 2019-10-16T14:36:41.177

Reputation: 2 534

1@Arnauld, it does not. Thanks for poingin out. Have updated. – Wernisch – 2019-10-29T10:34:52.203

Just wanted to let you know that the indicated solution for the needle character is not quite correct. You should switch to CHAR(MOD(E1+93*RAND()+1,95)+32) to insure that your solution covers all possible combinations of needle and haystack – Taylor Scott – 2019-11-22T20:21:40.973

2

Pyth, 56 50 48 41 bytes

JEKE=TE=Yrd\~=Zh.SYVJVQ ?qHK?qNTpeYpZpZ)d

I'm somewhat struggling to golf Pyth, but posting this to force myself to learn.

Edit 1: Golfed it down a bit, and made it an actual solution -6 bytes

Edit 2: Looked at it after posting it and realized a few bytes save by ignoring space. -2 bytes

Edit 3: Today I learned about character ranges, which shortens things significantly. -7 bytes

famous1622

Posted 2019-10-16T14:36:41.177

Reputation: 451

1

PHP, 113 109 bytes

for([,$w,$h,$x,$y]=$argv,$a=range(' ','~'),shuffle($a);$i++<$h;print"
")for(;$$i++<$w;)echo$a[$i-$y||$$i-$x];

Try it online!

Pass inputs as command arguments ($argv) in order of w, h, x and y. The x and y are one-indexed.

for(
  [,$w,$h,$x,$y]=$argv, // put inputs from $argv array into 4 short named variables
  $a=range(' ','~'),    // create $a array containing printable ASCII characters
  shuffle($a);          // shuffle the array
  $i++<$h;              // loop $h times (rows)
  print"\n"             // print a newline after every row
)
  for(;$$i++<$w;)       // loop $w times (columns)
    echo                // print
      $a[               //   a character from $a (1st char for needle and 2nd for heystack)
        $i-$y ||        //   when row and y don't match
        $$i-$x          //   or when col and x don't match (will be false only for needle)
      ];

Night2

Posted 2019-10-16T14:36:41.177

Reputation: 5 484

1

Add++, 65 bytes

D,g,?!,
L,c95Rdb[€BXd¦=BFV#@G+b[95€Ω%31€+€CA€RbU‽g$€=$€Ω:A$pbUp$T

Try it online!

Takes input as [y x] and [w h]. x and y are 1-indexed. Outputs a list of lines.

Added 17 bytes to make sure the needle is distinct.

How it works

We start by generating two ranges from \$1\$ to \$95\$ inclusive, before choosing a random value from each. If the two values are equal, we add one to the one of them. We then add \$31\$ to each, yielding two characters ord points in the ASCII range. Finally, we convert them to characters.

Next, we generate a list of all co-ordinates in the grid, and compare them with [y x]. If the co-ordinates match, we yield \$1\$, otherwise \$0\$. Next, we index each of these \$1\$s and \$0\$s into the two characters, creating a grid of \$0\$ characters with 1 \$1\$ character in it at [y x]. Finally, we retrieve the width and split the grid into that many rows.

caird coinheringaahing

Posted 2019-10-16T14:36:41.177

Reputation: 13 702

1

SOGL, 18 bytes

 ~Δψ] ~Δψ⁴⁴=}A*∙až

Try it here! 1-indexed.

dzaima

Posted 2019-10-16T14:36:41.177

Reputation: 19 048

1

C# (Visual C# Interactive Compiler), 145 bytes

(a,b,c,d)=>{int l=0;for(var j=Enumerable.Range(32,95).OrderBy(k=>Guid.NewGuid()).ToList();l<a*b;)Write((char)j[l==c*a+d?1:0]+(++l%a<1?"\n":""));}

Try it online!

Embodiment of Ignorance

Posted 2019-10-16T14:36:41.177

Reputation: 7 014

1

Icon, 119 bytes

procedure f(w,h,x,y)
until m:=char(32+?95)&n:=char(32+?95)&m~==n
t:=[];1to h&put(t,repl(m,w))&\z
t[y,x]:=n
return t
end

Try it online!

xand yare 1-indexed

Galen Ivanov

Posted 2019-10-16T14:36:41.177

Reputation: 13 815

1

Python 3, 137 bytes

lambda w,h,x,y,c=chr:"\n".join([c(a)*w,c(a)*x+c(n)+c(a)*(w-x-1)][r==y]for r in range(h));a,n=__import__("random").sample(range(32,127),2)

Try it online!

Uses zero-based indexing for the needle position.

Matthew Jensen

Posted 2019-10-16T14:36:41.177

Reputation: 713

from random import* is shorter than __import__("random"). 136 bytes. – Value Ink – 2019-10-17T00:54:46.093

1

Perl 6, 57 bytes

{(' '..'~').pick(2)[0 xx$^a*$^b-1,1;*].pick(*).rotor($a)}

Try it online!

Jo King

Posted 2019-10-16T14:36:41.177

Reputation: 38 234

1

Charcoal, 17 bytes

UONN‽γJNN‽Φγ¬⁼ιKK

Try it online! Link is to verbose version of code. Explanation:

UONN‽γ

Draw a rectangle of the given width and height using a random printable ASCII character.

JNN

Jump to the 0-indexed position of the needle.

‽Φγ¬⁼ιKK

Print a random printable ASCII character, but filtering out the character under the cursor.

Neil

Posted 2019-10-16T14:36:41.177

Reputation: 95 035

1

K (oK), 27 23 bytes

-4 bytes thanks to ngn!

{`c$(32+-2?95)x#&/y=!x}

Try it online!

0-indexed x and y

Similar to Dzaima's APL and Jonah's J solutions.

Galen Ivanov

Posted 2019-10-16T14:36:41.177

Reputation: 13 815

1(x/y)=x#!*/x -> x#&/y=!x – ngn – 2019-10-19T17:17:03.560

@ngn That's much better than my naive solution. Thanks! – Galen Ivanov – 2019-10-19T18:34:40.150

@ngn Clever use of the odometer for 2d matching! – Galen Ivanov – 2019-10-19T18:47:41.710

1

Red, 156 bytes

func[w h x y][c: :collect p: take/part random c[repeat i 95[keep to sp 32 + i]]2
c[repeat i h[keep/only c[repeat j w[keep pick p i * w + j
=(y * w + x)]]]]]

Try it online!

x and y are 1-indexed. Returns a list of strings.

Readable:

f: func [w h x y] [
    c: take/part random collect [
        repeat i 95 [
            keep to sp 32 + i
        ]
    ] 2
    collect[
        repeat i h [
            keep/only collect [
                repeat j w [
                    keep pick c i * w + j = (y * w + x)
                ]
            ]
        ]
    ]
]

Galen Ivanov

Posted 2019-10-16T14:36:41.177

Reputation: 13 815

1

Python 2, 144 132 131 bytes

from random import*
i,j,k,l=input()
n,h=sample(range(32,127),2)
for x in range(j):a=[chr(n)]*i;a[k]=chr((n,h)[x==l]);print`a`[2::5]

Try it online!

Corrected the problem with the guaranteed uniqueness of the characters and saved 12 bytes along the way.

ElPedro

Posted 2019-10-16T14:36:41.177

Reputation: 5 301

1

I liked the idea of this solution well enough that I shaved off 3 more bytes for you: https://tio.run/##JYxBCoMwEEX3OUUQhIzOxthSEHKS4EJaraPJJKQp2NOn0q4@vPf48ZPXwLqUJQUv08SPc8jHkHIjCDfc0Rni@M4KBONqXpOPblZn@ZxVr7HTN0ANYglJHpJY/s0GQ0zEuarvVUO1UozQ7K2y58doD2PciND@KIEdaCzlihfssfsC

– quintopia – 2019-10-30T09:16:58.997

Nice and also different enough for you to post as your own if you wish :) – ElPedro – 2019-10-30T12:28:34.190

Eh, it's not that different. It is a direct modification of yours edited directly on TIO. Posting it separately would have been actual effort. – quintopia – 2019-10-30T19:02:47.000

1

Forth (gforth), 140 bytes

include random.fs
: x 95 random 32 + ;
: f x -rot 0 do cr dup 0 do 2over i j d= >r over r> if begin x 2dup - until nip then emit loop loop ;

Try it online!

0-indexed

Code Explanation

include random.fs        \ import the random library

\ Generate a random number in range 32 to 126 inclusive
: x                      \ start a new word definition
  95 random              \ generate a random number between 0 and 94
  32 +                   \ add 32
;                        \ end word definition

: f                      \ start a new word definition
  x -rot                 \ generate a random number for the haystack, then move it
  0 do                   \ loop from 0 to h-1 (inclusive)
    cr                   \ output a newline
    dup 0 do             \ loop from 0 to w-1 (inclusive)
      2over i j d=       \ check if this is the needle square
      >r over r>         \ hide result, grab a copy of the haystack char, then grab result back
      if                 \ if it is a needle
        begin            \ begin indefinite loop
          x 2dup -       \ generate a new random number and compare to haystack char
        until            \ only end loop when values differ
        nip              \ drop haystack char
      then               \ end if block
      emit               \ output ascii char for value on top of stack
    loop                 \ end row loop
  loop                   \ end column loop
;                        \ end word definition

reffu

Posted 2019-10-16T14:36:41.177

Reputation: 1 361

1

C (clang), 87 bytes

f(w,h,x,y){x+=y*w;h*=++w;for(y=time(0)%9023;h--;)putchar(h%w?(x--?y+1:y%96)%95+32:10);}

Try it online!

Stealing from @Arnauld answer

AZTECCO

Posted 2019-10-16T14:36:41.177

Reputation: 2 441

1

Japt -R,34 30 29 24 bytes

;E=öx)ÎpU*V hW*U+XEg1)òU

Try it

5 Bytes saved thanks to @Shaggy.

Inputs are U,V => size , W,X => needle coords 0 indexed

 ;E=   // set of printable characters 
     öx) // random permutation 
 Î // => g0  pU*V    repeats U*V times first element of set
           hW*U+XEg1) // overwrite at W,X with 2nd element 
                      òU // split

AZTECCO

Posted 2019-10-16T14:36:41.177

Reputation: 2 441

@Shaggy my first try, the best I can do, any suggestions are implicitly welcome! – AZTECCO – 2019-10-20T20:49:56.293

1

A few quick savings for you here.

– Shaggy – 2019-10-22T09:11:34.843

Thanks @Shaggy! The good thing is that I 've understood your improvements, though I'm still far from a good usage of this language, maybe due to my poor experience in JS – AZTECCO – 2019-10-22T13:34:58.037

you don't really need a JS background to learn Japt. – Shaggy – 2019-10-22T17:56:47.683

1

05AB1E, 15 bytes

žQΩIPמQΩIPǝ¹нô

Coordinates are 1-indexed. Outputs as a list of lines.

Try it online (» in the footer joins the list of strings by newlines to pretty-print, feel free to remove it to see the actual output).

Explanation:

žQ              # Push all printable ASCII characters
  Ω             # Pop and push a random character
   IP           # Push the first input (rectangle-size), and take its product
     ×          # Repeat the random character that many times as string
      žQΩ       # Push a random character again
         IP     # Push the second input (1-based coordinate), and take its product as well
           ǝ    # Insert the random character at this (0-based) index into the string
            ¹н  # Push the first input again, and only leave its first value (width)
              ô # Split the string into parts of that size
                # (after which the resulting list of strings it output implicitly as result)

Kevin Cruijssen

Posted 2019-10-16T14:36:41.177

Reputation: 67 575

0

C (clang), 130 117 116 109 106 bytes

c[2];f(w,h,x,y){x+=y*w;for(h*=++w;y++<h|*c==c[1];)c[y%2]=time(0)%94+33;for(;h--;)printf(h%w?c+!x--:"\n");}

Try it online!

Saved 13 thanks to @ceilingcat Didn't thought using just only time() was enough And also didn't thought printf accepted a int pointer as a format string!

Needle is 0 indexed

c[2]; // needle and hay stored in array 
f(w,h,x,y){
 x+=y*w; // sets counter for needle (x no more needed)
 for(
     h*=++w; // while incrementing w for newline sets counter for haystack 
     y++<h  // more than 2 iterations to fill array
     |*c==c[1]; // until they're different 
     )
     c[y%2]=time(0)%94+33; // assign value to array (I've excluded spaces )
 for( ;h--; ) printf(h%w?c+!x--:"\n")
 // output: on h%w =0 => newline 
 //              if  x != 0 => hay
 //              when x=0 => needle 
 //              and continue to finish haystack 

AZTECCO

Posted 2019-10-16T14:36:41.177

Reputation: 2 441

0

Zsh, 108 bytes

Needle location is 1-indexed

repeat $2 : $[h=r++?h:RANDOM%95]&&(repeat $1 s+=${(#)$((n=r-$4||++c-$3?h:(n=RANDOM%94)+(n>=h),32+n))};<<<$s)

Try it online!

repeat $2
  # set hay when row is 0 (shorter than setting it before due to the cost of "(( ))")
  # ": $[  ]" always exits true. "((  ))" would exit false if hay == 0
  : $[hay = row++ ? hay : RANDOM % 95] && (
    # inner loop in (subshell), $str and $col will be empty every time
    repeat $1
      # ${(#)$((x))} expands to the Unicode character at codepoint $x
      str+=${(#)$((offset =
        row - $4 || ++col - $3
        ? hay
        : (offset = RANDOM % 94) + (offset >= hay),
        32 + offset
      ))}
      <<< $str
  )

Proof of correctness by exhaustion, for all combinations of RANDOM%95 and RANDOM%94.

GammaFunction

Posted 2019-10-16T14:36:41.177

Reputation: 2 838