15
\$\begingroup\$

Introduction

Given this visualization of a playing field:

(0,0)
+----------------------+(map_width, 0)
|           A          |
|-----+-----------+----|
|  D  |     W     | B  |
|-----+-----------+----|
|           C          |
+----------------------+(map_width, map_height)
(0, map_height)

The entire map the game is played on is the rectangle with the corner coordinates (0,0) and (map_width, map_height). The points eligible for spawning enemies is the Union $$S = \bigcup (A, B, C, D) $$

The Challenge

Write code that returns a random point(x, y) that is guaranteed to be inside S. Your code cannot introduce any additional bias, meaning that the probability of each coordinate is uniformly distributed given the assumption that your choice of generating randomness (e.g. function|library|dev/urandom) is unbiased.

Shortest solutions in bytes win!

Input

You will be given a total of 6 positive integer input variables in order: map_width, map_height, W_top_left_x, W_top_left_y, W_width, W_height. You can assume that the (calculated) surface area of all regions(A,B,C,D,W) is each >10, so there are no empty spaces/regions.

Example Input: 1000, 1000, 100, 100, 600, 400

Te input has to contain the 6 values described above but it can be passed as fewer numbers of arguments and in any order. For instance passing (map_width, map_height) as python tuple is allowed. What is not allowed of course are calculated parameters like the bottom right point of the W.

Output

2 randomly generated integers (x, y) where

$$(0 \leq x \lt \text{map_width}) \land \neg (\text{W_top_left_x} \leq x \lt \text{W_top_left_x} + \text{view_width})$$

OR

$$(0 \leq y \lt \text{map_height}) \land \neg (\text{W_top_left_y} \leq y \lt \text{W_top_left_y} + \text{view_height})$$

meaning at least one of the above logical expressions has to be true.

Examples

Input                                    Output(valid random samples)

1000 1000 100 100 600 400                10 10
1000 1000 100 100 600 400                800 550
1000 1000 100 100 600 400                800 10
1000 1000 100 100 600 400                10 550

For details and limitations for input/output please refer to the default input/output rules

\$\endgroup\$
  • \$\begingroup\$ I think you should explicitly state that the output coordinates are integers (which I infer as your implicit intention). \$\endgroup\$ – agtoever Aug 6 at 15:08
  • 1
    \$\begingroup\$ Can we use the default input/output rules? \$\endgroup\$ – Nick Kennedy Aug 6 at 19:02
  • 1
    \$\begingroup\$ @agtoever it says so in the "output" section; 2 randomly generated integers (x, y) \$\endgroup\$ – Giuseppe Aug 6 at 23:07
  • 1
    \$\begingroup\$ may we take inputs in a different (consistent) order? \$\endgroup\$ – attinat Aug 7 at 2:03
  • \$\begingroup\$ @agtoever yes output has to be an integers as stated in the "output" section. \$\endgroup\$ – jaaq Aug 7 at 7:41

14 Answers 14

7
\$\begingroup\$

Python 2, 114 106 102 101 bytes

lambda w,h,X,Y,W,H:choice([(i%w,i/w)for i in range(w*h)if(W>i%w-X>-1<i/w-Y<H)<1])
from random import*

Try it online!

\$\endgroup\$
  • \$\begingroup\$ I am not sure but I think it should be [i%w, i/w] because the range w*h/w=h but x is tied to the width in this example not the height. \$\endgroup\$ – jaaq Aug 7 at 7:32
  • \$\begingroup\$ @jaaq Yeah, you're right. Fixed now, thanks :) \$\endgroup\$ – TFeld Aug 7 at 7:35
  • \$\begingroup\$ I just checked the contents of the list you generate and it seems that your solution is incorrect. Plotting the points shows that all values are along a line and do not fill out the entire region of S as intended. Also the list you generate contains non-integer values. \$\endgroup\$ – jaaq Aug 7 at 9:20
  • \$\begingroup\$ @jaaq I'm not sure what you mean? The coordinates are always integers, and not on a line (eg) \$\endgroup\$ – TFeld Aug 7 at 9:27
  • 1
    \$\begingroup\$ @jaaq In Python 2, a/b is already floor division, if a and b are integers (which they are here). \$\endgroup\$ – TFeld Aug 7 at 10:37
4
\$\begingroup\$

R, 89 73 bytes

function(w,h,K,D,`*`=sample){while(all((o<-c(0:w*1,0:h*1))<=K+D&o>K))0
o}

Try it online!

Takes input as width,height,c(X,Y),c(W,H).

Samples from \$[0,w]\times[0,h]\$ uniformly until it finds a point outside the inner rectangle.

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

05AB1E, 23 21 20 18 17 bytes

L`â<ʒ²³+‹y²@«P≠}Ω

Input is in the format [map_width, map_height], [W_top_left_x, W_top_left_y], [W_width, W_height].

Thanks to @Grimy for -1 byte, and also for making me realize I introduced a bug after my latest edit.

Try it online, output 10 possible outputs at the same time or verify all possible coordinates. (Minor note: I've decreased the example input by a factor 10, because the filter and random choice builtin arer pretty slow for big lists.)

Explanation:

The inputs map_width, map_height, [W_top_left_x, W_top_left_y], [W_width, W_height] are referred to as [Wm, Hm], [x, y], [w, h] below:

L          # Convert the values of the first (implicit) input to an inner list in
           # the range [1, n]: [[1,2,3,...,Wm],[1,2,3,....,Hm]]
 `         # Push both inner lists separated to the stack
  â        # Get the cartesian product of both lists, creating each possible pair
   <       # Decrease each pair by 1 to make it 0-based
           # (We now have: [[0,0],[0,1],[0,2],...,[Wm,Hm-2],[Wm,Hm-1],[Wm,Hm]])
    ʒ      # Filter this list of coordinates [Xr, Yr] by:
     ²³+   #  Add the next two inputs together: [x+w, y+h]
        ‹  #  Check for both that they're lower than the coordinate: [Xr<x+w, Yr<y+h]
     y     #  Push the coordinate again: [Xr, Yr]
      ²    #  Push the second input again: [x, y]
       @   #  Check for both that the coordinate is larger than or equal to this given 
           #  input: [Xr>=x, Yr>=y] (the w,h in the input are ignored)
     «     #  Merge it with the checks we did earlier: [Xr<x+w, Yr<y+h, Xr>=x, Yr>=y]
      P≠   #  And check if any of the four is falsey (by taking the product and !=1,
           #  or alternatively `ß_`: minimum == 0)
    }Ω     # After the filter: pick a random coordinate
           # (which is output implicitly as result)
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks for adding the verify part :) great solution! \$\endgroup\$ – jaaq Aug 7 at 9:50
  • 1
    \$\begingroup\$ @jaaq Thanks! I've used the verifier myself after my initial version, which is when I noticed a bug I had to fix, since it was including coordinate [map_height, 0] as possible random output without the ¨. :) \$\endgroup\$ – Kevin Cruijssen Aug 7 at 10:01
  • \$\begingroup\$ *ݨ¹‰ could be L`â< by taking the first two inputs as [map_height, map_width]. Also II could be Š, unless I missed something. \$\endgroup\$ – Grimmy Aug 8 at 15:47
  • \$\begingroup\$ @Grimy Thanks for the L`â<. As for the II+ to Š+, you're indeed right that it would be the same.. Unfortunately I made an error myself and it should have been ²³+ instead of II+, since it would use the third input for both I (just like it would take two times the third input with Š) after the first iteration of the filter.. So implicitly thanks for making me realize I had a bug. :) \$\endgroup\$ – Kevin Cruijssen Aug 8 at 16:58
3
\$\begingroup\$

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

(a,b,c,d,e,f)=>{int g=c,h=d;for(var z=new Random();g>=c&g<e+c|h>=d&h<f+d;h=z.Next(b))g=z.Next(a);return(g,h);}

Try it online!

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

PowerShell, 85 73 bytes

-12 bytes thanks to mazzy

param($a,$b,$x,$y,$w,$h)$a,$b|%{0..--$x+($x+$w+2)..$_|random
$x,$w=$y,$h}

Try it online!

Nice simple answer which cobbles together an array made of the range of values for each dimension and then picks one randomly for x and y. Manages to reuse most of the code by first processing x, then overwriting $x with $y and running it again.

\$\endgroup\$
  • 1
    \$\begingroup\$ you can save a few bytes Try it online! \$\endgroup\$ – mazzy Aug 6 at 17:21
  • 1
    \$\begingroup\$ @mazzy I actually did stumble across the range optimization but applied it backwards, saving 0 bytes. \$\endgroup\$ – Veskah Aug 6 at 17:47
1
\$\begingroup\$

Julia, 76 71 67 bytes

f(w,h,a,b,c,d)=rand(setdiff((0:w-1)'.=>0:h-1,(a:a+c-1)'.=>b:b+d-1))

Try it online!

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

Jelly, 11 bytes

p/’$€+2¦ḟ/X

Try it online!

A dyadic link that takes two arguments, [map_width, map_height], [W_width, W_height] and W_left, W_top and returns a randomly selected point meeting the requirements.

Explanation

   $€       | For each of member of the left argument, do the following as a monad:
p/          | - Reduce using Cartesian product (will generate [1,1],[1,2],... up to the width and height of each of the rectangles)
  ’         | - Decrease by 1 (because we want zero-indexing)
     +2¦    | Add the right argument to the second element of the resulting list
        ḟ/  | Reduce by filtering members of the second list from the first
          X | Select a random element
\$\endgroup\$
1
\$\begingroup\$

Python 2, 100 bytes

Input should be in the form of ((map_width, W_top_left_x, W_width),(map_height, W_top_left_y, W_height))

Output is given in the form: [[x],[y]]

lambda C:[c(s(r(i[0]))-s(r(i[1],i[1]+i[2])),1)for i in C]
from random import*;c=sample;r=range;s=set

Try it online!

Random outputs obtained from the example input:

[[72], [940]]
[[45], [591]]
[[59], [795]]
[[860], [856]]
[[830], [770]]
[[829], [790]]
[[995], [922]]
[[23], [943]]
[[761], [874]]
[[816], [923]]
\$\endgroup\$
1
\$\begingroup\$

Java (OpenJDK 8), 100 bytes

W->H->r->{int x=0,y=0;for(;r.contains(x+=W*Math.random(),y+=H*Math.random());x=y=0);return x+","+y;}

Try it online!

Uses java.awt.Rectangle as holder of some of the parameters. Naturally, those use int fields, and not float or double.

\$\endgroup\$
  • 1
    \$\begingroup\$ Oh, nice way to take the challenge literally with the Rectangle#contains builtin! :D \$\endgroup\$ – Kevin Cruijssen Aug 8 at 17:03
1
\$\begingroup\$

Wolfram Language (Mathematica), 84 68 60 bytes

RandomChoice[g=Join@@List~Array~##&;#~g~0~Complement~g@##2]&

Try it online!

Take inputs as {map_width, map_height}, {W_width, W_height}, {W_top_left_x, W_top_left_y}.

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

Charcoal, 55 43 bytes

NθNηFE²N⊞υ⟦ιN⟧I‽ΦE×θη⟦﹪ιθ÷ιθ⟧⊙υ∨‹§ιμ§λ⁰¬‹§ιμΣλ

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

NθNη

Input the map size. (If they were last, I could input the height inline for a 1-byte saving.)

FE²N⊞υ⟦ιN⟧

Input the inner rectangle. (If I could input in the order left, width, top, height then I could use F²⊞υE²N for a 3-byte saving.)

E×θη⟦﹪ιθ÷ιθ⟧

Generate a list of all co-ordinates in the field.

Φ...⊙υ∨‹§ιμ§λ⁰¬‹§ιμΣλ

Filter out entries where both co-ordinates lie inside the rectangle.

I‽...

Print a random element of those that are left.

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

Perl 5 -ap, 84 bytes

sub c{($c=0|rand((pop)+($l=pop)-"@_"))<$l?$c:$c+"@_"-$l}say c@F[4,2,0];$_=c@F[5,3,1]

Try it online!

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

Scala, 172 bytes

Randomness? Gotcha.

(a:Int,b:Int,c:Int,d:Int,e:Int,f:Int)=>{var r=new scala.util.Random
var z=(0,0)
do{z=(r.nextInt(a),r.nextInt(b))}while((c to e+c contains z._1)|(d to e+d contains z._2))
z}

A fun implementation I could think of.
How it works: Generate a random pair in the map. If it is in the inner rectangle, try again.
Try it online!

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

J, 54 47 45 39 bytes

(0?@{[)^:((-1&{)~(<*/@,0<:[)2{[)^:_{~&1

Try it online!

Take input as a 3 x 2 grid like:

grid_height  grid_width
inner_top    inner_left
inner_height inner_width
  • Pick a random point on the entire grid: 0?@{[
  • Shift it left and down by the upper-left point of the interior rectangle: (-1&{)~
  • Return to step 1 if the chosen spot is within (<*/@,0<:[) the similarly shifted interior rectangle 2{[. Otherwise return the original, unshifted random point.
  • Seed the whole process with a point we know is invalid, namely the upper left point of the interior rectangle, defined by elements 2 and 3 of the input list: {~&1

Another approach, 45 bytes

{.#:i.@{.(?@#{])@-.&,([:<@;&i./{:){1&{|.i.@{.

Try it online!

This one is conceptually simpler, and doesn't bother with looping. Instead, we construct a matrix of all the numbers 0 to (w x h), shift it by the inner starting point, grab just the points in the (0, 0) to (inner w, innner h) subgrid, remove them from the overall grid after flattening both, pick one at random from the remainder, and convert the integer back into a point using divmod <.@% , |~

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