python生成范围内随机数,在python中生成超出范围的随机数

I'm currently working on a pygame game and I need to place objects randomly on the screen, except they cannot be within a designated rectangle. Is there an easy way to do this rather than continuously generating a random pair of coordinates until it's outside of the rectangle?

Here's a rough example of what the screen and the rectangle look like.

______________

| __ |

| |__| |

| |

| |

|______________|

Where the screen size is 1000x800 and the rectangle is [x: 500, y: 250, width: 100, height: 75]

A more code oriented way of looking at it would be

x = random_int

0 <= x <= 1000

and

500 > x or 600 < x

y = random_int

0 <= y <= 800

and

250 > y or 325 < y

解决方案

It requires a bit of thought to generate a uniformly random point with these constraints. The simplest brute force way I can think of is to generate a list of all valid points and use random.choice() to select from this list. This uses a few MB of memory for the list, but generating a point is very fast:

import random

screen_width = 1000

screen_height = 800

rect_x = 500

rect_y = 250

rect_width = 100

rect_height = 75

valid_points = []

for x in range(screen_width):

if rect_x <= x < (rect_x + rect_width):

for y in range(rect_y):

valid_points.append( (x, y) )

for y in range(rect_y + rect_height, screen_height):

valid_points.append( (x, y) )

else:

for y in range(screen_height):

valid_points.append( (x, y) )

for i in range(10):

rand_point = random.choice(valid_points)

print(rand_point)

It is possible to generate a random number and map it to a valid point on the screen, which uses less memory, but it is a bit messy and takes more time to generate the point. There might be a cleaner way to do this, but one approach using the same screen size variables as above is here:

rand_max = (screen_width * screen_height) - (rect_width * rect_height)

def rand_point():

rand_raw = random.randint(0, rand_max-1)

x = rand_raw % screen_width

y = rand_raw // screen_width

if rect_y <= y < rect_y+rect_height and rect_x <= x < rect_x+rect_width:

rand_raw = rand_max + (y-rect_y) * rect_width + (x-rect_x)

x = rand_raw % screen_width

y = rand_raw // screen_width

return (x, y)

The logic here is similar to the inverse of the way that screen addresses are calculated from x and y coordinates on old 8 and 16 bit microprocessors. The variable rand_max is equal to the number of valid screen coordinates. The x and y co-ordinates of the pixel are calculated, and if it is within the rectangle the pixel is pushed above rand_max, into the region that couldn't be generated with the first call.

If you don't care too much about the point being uniformly random, this solution is easy to implement and very quick. The x values are random, but the Y value is constrained if the chosen X is in the column with the rectangle, so the pixels above and below the rectangle will have a higher probability of being chosen than pizels to the left and right of the rectangle:

def pseudo_rand_point():

x = random.randint(0, screen_width-1)

if rect_x <= x < rect_x + rect_width:

y = random.randint(0, screen_height-rect_height-1)

if y >= rect_y:

y += rect_height

else:

y = random.randint(0, screen_height-1)

return (x, y)

Another answer was calculating the probability that the pixel is in certain regions of the screen, but their answer isn't quite correct yet. Here's a version using a similar idea, calculate the probability that the pixel is in a given region and then calculate where it is within that region:

valid_screen_pixels = screen_width*screen_height - rect_width * rect_height

prob_left = float(rect_x * screen_height) / valid_screen_pixels

prob_right = float((screen_width - rect_x - rect_width) * screen_height) / valid_screen_pixels

prob_above_rect = float(rect_y) / (screen_height-rect_height)

def generate_rand():

ymin, ymax = 0, screen_height-1

xrand = random.random()

if xrand < prob_left:

xmin, xmax = 0, rect_x-1

elif xrand > (1-prob_right):

xmin, xmax = rect_x+rect_width, screen_width-1

else:

xmin, xmax = rect_x, rect_x+rect_width-1

yrand = random.random()

if yrand < prob_above_rect:

ymax = rect_y-1

else:

ymin=rect_y+rect_height

x = random.randrange(xmin, xmax)

y = random.randrange(ymin, ymax)

return (x, y)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值