Trying to generate 5 random items, sometimes generate 4
import random
twoDimMap = [["H", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"],
["-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"],
["-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"]]
items = 0
while items <= 4:
test = random.randrange(0, 3)
if test == 0:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "S"
if test == 1:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "R"
if test == 2:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "*"
# I couldn't think of an easier way to do this
if twoDimMap[0][0] != "H":
twoDimMap[0][0] = "H"
items -= 1
items += 1
print(twoDimMap)
Title explains it all pretty much (even though I know it isn't too descriptive :/), I am trying to make a game where the hero starts on the map at position [0],[0]. I can't work out why the hell I'm sometimes generating fewer items than other times.
Edit: Thanks for all of your feedback, and sorry for wasting your time with my stupid mistake :/. I'm going to blame it on the lack of coffee.
python random
|
show 4 more comments
import random
twoDimMap = [["H", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"],
["-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"],
["-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"]]
items = 0
while items <= 4:
test = random.randrange(0, 3)
if test == 0:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "S"
if test == 1:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "R"
if test == 2:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "*"
# I couldn't think of an easier way to do this
if twoDimMap[0][0] != "H":
twoDimMap[0][0] = "H"
items -= 1
items += 1
print(twoDimMap)
Title explains it all pretty much (even though I know it isn't too descriptive :/), I am trying to make a game where the hero starts on the map at position [0],[0]. I can't work out why the hell I'm sometimes generating fewer items than other times.
Edit: Thanks for all of your feedback, and sorry for wasting your time with my stupid mistake :/. I'm going to blame it on the lack of coffee.
python random
2
What do you mean by "generating fewer items than other times"?
– Jon Clements♦
Nov 12 at 0:22
I need to place 5 items in the list twoDimMap, an example of an instance wherein fewer items were placed is this: [['H', '-', 'S', '-', '-', '-'], ['-', '-', '-', '-', '-', '-'], ['', '-', '-', '-', '', '-'], ['-', '-', '-', '-', '-', '-'], ['S', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-']]
– Ch0w
Nov 12 at 0:23
Do not try to explain more in a comment. You can always edit your post, you know.
– usr2564301
Nov 12 at 0:24
4
This is probably caused by randomly getting the same x, y coordinates more than once.
– Håken Lid
Nov 12 at 0:24
1
I bet you generate 5 but one overwrites an earlier. So test if the contents of your new item are-
first.
– usr2564301
Nov 12 at 0:24
|
show 4 more comments
import random
twoDimMap = [["H", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"],
["-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"],
["-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"]]
items = 0
while items <= 4:
test = random.randrange(0, 3)
if test == 0:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "S"
if test == 1:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "R"
if test == 2:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "*"
# I couldn't think of an easier way to do this
if twoDimMap[0][0] != "H":
twoDimMap[0][0] = "H"
items -= 1
items += 1
print(twoDimMap)
Title explains it all pretty much (even though I know it isn't too descriptive :/), I am trying to make a game where the hero starts on the map at position [0],[0]. I can't work out why the hell I'm sometimes generating fewer items than other times.
Edit: Thanks for all of your feedback, and sorry for wasting your time with my stupid mistake :/. I'm going to blame it on the lack of coffee.
python random
import random
twoDimMap = [["H", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"],
["-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"],
["-", "-", "-", "-", "-", "-"], ["-", "-", "-", "-", "-", "-"]]
items = 0
while items <= 4:
test = random.randrange(0, 3)
if test == 0:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "S"
if test == 1:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "R"
if test == 2:
twoDimMap[random.randrange(0, 5)][random.randrange(0, 5)] = "*"
# I couldn't think of an easier way to do this
if twoDimMap[0][0] != "H":
twoDimMap[0][0] = "H"
items -= 1
items += 1
print(twoDimMap)
Title explains it all pretty much (even though I know it isn't too descriptive :/), I am trying to make a game where the hero starts on the map at position [0],[0]. I can't work out why the hell I'm sometimes generating fewer items than other times.
Edit: Thanks for all of your feedback, and sorry for wasting your time with my stupid mistake :/. I'm going to blame it on the lack of coffee.
python random
python random
edited Nov 12 at 1:10
Håken Lid
10.5k62441
10.5k62441
asked Nov 12 at 0:18
Ch0w
184
184
2
What do you mean by "generating fewer items than other times"?
– Jon Clements♦
Nov 12 at 0:22
I need to place 5 items in the list twoDimMap, an example of an instance wherein fewer items were placed is this: [['H', '-', 'S', '-', '-', '-'], ['-', '-', '-', '-', '-', '-'], ['', '-', '-', '-', '', '-'], ['-', '-', '-', '-', '-', '-'], ['S', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-']]
– Ch0w
Nov 12 at 0:23
Do not try to explain more in a comment. You can always edit your post, you know.
– usr2564301
Nov 12 at 0:24
4
This is probably caused by randomly getting the same x, y coordinates more than once.
– Håken Lid
Nov 12 at 0:24
1
I bet you generate 5 but one overwrites an earlier. So test if the contents of your new item are-
first.
– usr2564301
Nov 12 at 0:24
|
show 4 more comments
2
What do you mean by "generating fewer items than other times"?
– Jon Clements♦
Nov 12 at 0:22
I need to place 5 items in the list twoDimMap, an example of an instance wherein fewer items were placed is this: [['H', '-', 'S', '-', '-', '-'], ['-', '-', '-', '-', '-', '-'], ['', '-', '-', '-', '', '-'], ['-', '-', '-', '-', '-', '-'], ['S', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-']]
– Ch0w
Nov 12 at 0:23
Do not try to explain more in a comment. You can always edit your post, you know.
– usr2564301
Nov 12 at 0:24
4
This is probably caused by randomly getting the same x, y coordinates more than once.
– Håken Lid
Nov 12 at 0:24
1
I bet you generate 5 but one overwrites an earlier. So test if the contents of your new item are-
first.
– usr2564301
Nov 12 at 0:24
2
2
What do you mean by "generating fewer items than other times"?
– Jon Clements♦
Nov 12 at 0:22
What do you mean by "generating fewer items than other times"?
– Jon Clements♦
Nov 12 at 0:22
I need to place 5 items in the list twoDimMap, an example of an instance wherein fewer items were placed is this: [['H', '-', 'S', '-', '-', '-'], ['-', '-', '-', '-', '-', '-'], ['', '-', '-', '-', '', '-'], ['-', '-', '-', '-', '-', '-'], ['S', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-']]
– Ch0w
Nov 12 at 0:23
I need to place 5 items in the list twoDimMap, an example of an instance wherein fewer items were placed is this: [['H', '-', 'S', '-', '-', '-'], ['-', '-', '-', '-', '-', '-'], ['', '-', '-', '-', '', '-'], ['-', '-', '-', '-', '-', '-'], ['S', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-']]
– Ch0w
Nov 12 at 0:23
Do not try to explain more in a comment. You can always edit your post, you know.
– usr2564301
Nov 12 at 0:24
Do not try to explain more in a comment. You can always edit your post, you know.
– usr2564301
Nov 12 at 0:24
4
4
This is probably caused by randomly getting the same x, y coordinates more than once.
– Håken Lid
Nov 12 at 0:24
This is probably caused by randomly getting the same x, y coordinates more than once.
– Håken Lid
Nov 12 at 0:24
1
1
I bet you generate 5 but one overwrites an earlier. So test if the contents of your new item are
-
first.– usr2564301
Nov 12 at 0:24
I bet you generate 5 but one overwrites an earlier. So test if the contents of your new item are
-
first.– usr2564301
Nov 12 at 0:24
|
show 4 more comments
6 Answers
6
active
oldest
votes
You're only checking if the player is overwritten, not if the objects are, you should first get the random coordinates and then check if something's there.
while items <= 4:
test = random.randrange(0,3)
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
if test == 0:
twoDimMap[x][y] = "S"
if test ==1:
twoDimMap[x][y] = "R"
if test == 2:
twoDimMap[x][y] = "*"
items += 1
a more compact solution as suggested in the comments is
while items <= 4:
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = random.choice('SR*')
items += 1
4
Or unless something else is going to happen with thoseif
s... you can dotwoDimMap[x][y] = random.choice('SR*')
. Also, instead of the while, dofor items in range(5)
... then you can't forget to increment the counter.
– Jon Clements♦
Nov 12 at 0:27
the only problem I saw with changing thewhile
with afor
loop is that there would be less objects in the end if you get the samex
andy
, so thefor
solution would also require awhile
inside to generate unrepeated coordinates.
– vlizana
Nov 12 at 0:33
Ahh... good point... Can still simplify theif
s though... maybe just maketest = random.choice('SR*')
and then assigntest
inside the single if
– Jon Clements♦
Nov 12 at 0:33
added in the response, thanks
– vlizana
Nov 12 at 0:39
add a comment |
Since the problem space is so small, it's probably not a terrible idea to just generate three of them that are guaranteed unique.
valid_locations = (tup for tup in itertools.product(range(5), repeat=2) if tup != (0, 0))
items = ["S", "R", "*"]
choices = [(random.choice(items), loc) for loc in random.sample(valid_locations, 3)]
for item, (x, y) in choices:
twoDimMap[y][x] = item
random.sample(collection, n)
guarantees n
non-duplicated random results from collection
. random.choice(collection)
gives you a random element from collection
.
I was thinking similarly but you don't needitertools.product
here... I think you should be able to jump straight to:choices = ((random.choice(items), divmod(pos, 5)) for pos in random.sample(range(1, 25), 5))
...
– Jon Clements♦
Nov 12 at 0:47
@JonClements true, and great work avoiding the(0, 0)
with that, but it's obviously a bit more of a logical leap to see that.
– Adam Smith
Nov 12 at 0:48
1
Yeah... and if the H isn't going to be the first or last - it's doesn't work... but...
– Jon Clements♦
Nov 12 at 0:49
@JonClements but it's super neat :D
– Adam Smith
Nov 12 at 0:52
add a comment |
Sometimes randrange(0, 5)
returns the same thing several times, thus some point is reassigned.
This could be solved by generating the coordinates together with the type and only executing the rest of the loop if that point is currently unoccupied. This would also eliminate the need for a separate (0,0) test-case.
While this answer is good, giving a way to solve it would be preferable.
– Olivier Melançon
Nov 12 at 0:25
Argh, of course. How did I forget about that :/
– Ch0w
Nov 12 at 0:26
add a comment |
To avoid overwriting previously placed items, you can use random.sample
, which will pick random items from the input sample without replacement.
There are several other convenient functions for sequences in the random
module.
I've rewritten your code and turned it into a function that can generate rectangular maps of any size and number and type of items.
import random
def make_map(width, height, number_of_items, items='SR*'):
"""Create a map with the Hero in top left corner
and random items spread around"""
# build an empty map using a nested list comprehension
game_map = [['-' for x in range(width)] for y in range(height)]
# place the hero at coordinates 0, 0
game_map[0][0] = 'H'
# possible item positions, excluding 0, where the hero is.
positions = range(1, width * height)
# loop over n random choices from the available positions
for pos in random.sample(positions, number_of_items):
# convert pos to x, y coordinates using modular arithmetic
x, y = pos % width, pos // width
# select a random item to and place it at coordinates x, y
game_map[y][x] = random.choice(items)
return game_map
# generate a map. You can change the input arguments to vary size and items
game_map = make_map(6, 6, 5)
# convert the nested list to one string and print
print('n'.join(''.join(line) for line in game_map))
We use modular arithmetic to convert the position value which is a number in the range 1 to 36 into x,y coordinates on a 6×6 grid. This is a very common and useful operation in computer graphics.
x, y = pos % width, pos // width
This is such a common operation that python has a built-in function you can use for this exact thing.
y, x = divmod(pos, width)
I will not explain all of the code, but I encourage you to read through the answers and try to understand how every line works. You can learn a lot from reading other people's solutions to the same problem as you have solved yourself.
add a comment |
Less items are generated because there are times where the same coordinates are generated again. One way to avoid this is to check if the location already has an item before assigning it. This way, you will solve the issue of replacing your hero too.
import random
twoDimMap = [["H","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"]]
items = 0
item_list = ['S', 'R', '*']
while items <= 4:
x = random.randrange(0,5)
y = random.randrange(0,5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = item_list[random.randrange(0,3)]
items += 1
add a comment |
If your map isn't too big, you could use random.sample
to Choose at random from combinations.
twoDimMap = [list(line) for line in """
H-----
------
------
------
------
------""".split("n")]
width, height = len(twoDimMap[0]), len(twoDimMap)
allLocations = [(x, y) for x in range(width) for y in range(height) if (x, y) != (0, 0)]
for x, y in random.sample(allLocations, 5):
case = random.randrange(3)
twoDimMap[y][x] = "SR*"[case]
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53254564%2ftrying-to-generate-5-random-items-sometimes-generate-4%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
You're only checking if the player is overwritten, not if the objects are, you should first get the random coordinates and then check if something's there.
while items <= 4:
test = random.randrange(0,3)
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
if test == 0:
twoDimMap[x][y] = "S"
if test ==1:
twoDimMap[x][y] = "R"
if test == 2:
twoDimMap[x][y] = "*"
items += 1
a more compact solution as suggested in the comments is
while items <= 4:
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = random.choice('SR*')
items += 1
4
Or unless something else is going to happen with thoseif
s... you can dotwoDimMap[x][y] = random.choice('SR*')
. Also, instead of the while, dofor items in range(5)
... then you can't forget to increment the counter.
– Jon Clements♦
Nov 12 at 0:27
the only problem I saw with changing thewhile
with afor
loop is that there would be less objects in the end if you get the samex
andy
, so thefor
solution would also require awhile
inside to generate unrepeated coordinates.
– vlizana
Nov 12 at 0:33
Ahh... good point... Can still simplify theif
s though... maybe just maketest = random.choice('SR*')
and then assigntest
inside the single if
– Jon Clements♦
Nov 12 at 0:33
added in the response, thanks
– vlizana
Nov 12 at 0:39
add a comment |
You're only checking if the player is overwritten, not if the objects are, you should first get the random coordinates and then check if something's there.
while items <= 4:
test = random.randrange(0,3)
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
if test == 0:
twoDimMap[x][y] = "S"
if test ==1:
twoDimMap[x][y] = "R"
if test == 2:
twoDimMap[x][y] = "*"
items += 1
a more compact solution as suggested in the comments is
while items <= 4:
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = random.choice('SR*')
items += 1
4
Or unless something else is going to happen with thoseif
s... you can dotwoDimMap[x][y] = random.choice('SR*')
. Also, instead of the while, dofor items in range(5)
... then you can't forget to increment the counter.
– Jon Clements♦
Nov 12 at 0:27
the only problem I saw with changing thewhile
with afor
loop is that there would be less objects in the end if you get the samex
andy
, so thefor
solution would also require awhile
inside to generate unrepeated coordinates.
– vlizana
Nov 12 at 0:33
Ahh... good point... Can still simplify theif
s though... maybe just maketest = random.choice('SR*')
and then assigntest
inside the single if
– Jon Clements♦
Nov 12 at 0:33
added in the response, thanks
– vlizana
Nov 12 at 0:39
add a comment |
You're only checking if the player is overwritten, not if the objects are, you should first get the random coordinates and then check if something's there.
while items <= 4:
test = random.randrange(0,3)
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
if test == 0:
twoDimMap[x][y] = "S"
if test ==1:
twoDimMap[x][y] = "R"
if test == 2:
twoDimMap[x][y] = "*"
items += 1
a more compact solution as suggested in the comments is
while items <= 4:
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = random.choice('SR*')
items += 1
You're only checking if the player is overwritten, not if the objects are, you should first get the random coordinates and then check if something's there.
while items <= 4:
test = random.randrange(0,3)
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
if test == 0:
twoDimMap[x][y] = "S"
if test ==1:
twoDimMap[x][y] = "R"
if test == 2:
twoDimMap[x][y] = "*"
items += 1
a more compact solution as suggested in the comments is
while items <= 4:
x = random.randrange(0, 5)
y = random.randrange(0, 5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = random.choice('SR*')
items += 1
edited Nov 12 at 0:38
answered Nov 12 at 0:26
vlizana
638215
638215
4
Or unless something else is going to happen with thoseif
s... you can dotwoDimMap[x][y] = random.choice('SR*')
. Also, instead of the while, dofor items in range(5)
... then you can't forget to increment the counter.
– Jon Clements♦
Nov 12 at 0:27
the only problem I saw with changing thewhile
with afor
loop is that there would be less objects in the end if you get the samex
andy
, so thefor
solution would also require awhile
inside to generate unrepeated coordinates.
– vlizana
Nov 12 at 0:33
Ahh... good point... Can still simplify theif
s though... maybe just maketest = random.choice('SR*')
and then assigntest
inside the single if
– Jon Clements♦
Nov 12 at 0:33
added in the response, thanks
– vlizana
Nov 12 at 0:39
add a comment |
4
Or unless something else is going to happen with thoseif
s... you can dotwoDimMap[x][y] = random.choice('SR*')
. Also, instead of the while, dofor items in range(5)
... then you can't forget to increment the counter.
– Jon Clements♦
Nov 12 at 0:27
the only problem I saw with changing thewhile
with afor
loop is that there would be less objects in the end if you get the samex
andy
, so thefor
solution would also require awhile
inside to generate unrepeated coordinates.
– vlizana
Nov 12 at 0:33
Ahh... good point... Can still simplify theif
s though... maybe just maketest = random.choice('SR*')
and then assigntest
inside the single if
– Jon Clements♦
Nov 12 at 0:33
added in the response, thanks
– vlizana
Nov 12 at 0:39
4
4
Or unless something else is going to happen with those
if
s... you can do twoDimMap[x][y] = random.choice('SR*')
. Also, instead of the while, do for items in range(5)
... then you can't forget to increment the counter.– Jon Clements♦
Nov 12 at 0:27
Or unless something else is going to happen with those
if
s... you can do twoDimMap[x][y] = random.choice('SR*')
. Also, instead of the while, do for items in range(5)
... then you can't forget to increment the counter.– Jon Clements♦
Nov 12 at 0:27
the only problem I saw with changing the
while
with a for
loop is that there would be less objects in the end if you get the same x
and y
, so the for
solution would also require a while
inside to generate unrepeated coordinates.– vlizana
Nov 12 at 0:33
the only problem I saw with changing the
while
with a for
loop is that there would be less objects in the end if you get the same x
and y
, so the for
solution would also require a while
inside to generate unrepeated coordinates.– vlizana
Nov 12 at 0:33
Ahh... good point... Can still simplify the
if
s though... maybe just make test = random.choice('SR*')
and then assign test
inside the single if– Jon Clements♦
Nov 12 at 0:33
Ahh... good point... Can still simplify the
if
s though... maybe just make test = random.choice('SR*')
and then assign test
inside the single if– Jon Clements♦
Nov 12 at 0:33
added in the response, thanks
– vlizana
Nov 12 at 0:39
added in the response, thanks
– vlizana
Nov 12 at 0:39
add a comment |
Since the problem space is so small, it's probably not a terrible idea to just generate three of them that are guaranteed unique.
valid_locations = (tup for tup in itertools.product(range(5), repeat=2) if tup != (0, 0))
items = ["S", "R", "*"]
choices = [(random.choice(items), loc) for loc in random.sample(valid_locations, 3)]
for item, (x, y) in choices:
twoDimMap[y][x] = item
random.sample(collection, n)
guarantees n
non-duplicated random results from collection
. random.choice(collection)
gives you a random element from collection
.
I was thinking similarly but you don't needitertools.product
here... I think you should be able to jump straight to:choices = ((random.choice(items), divmod(pos, 5)) for pos in random.sample(range(1, 25), 5))
...
– Jon Clements♦
Nov 12 at 0:47
@JonClements true, and great work avoiding the(0, 0)
with that, but it's obviously a bit more of a logical leap to see that.
– Adam Smith
Nov 12 at 0:48
1
Yeah... and if the H isn't going to be the first or last - it's doesn't work... but...
– Jon Clements♦
Nov 12 at 0:49
@JonClements but it's super neat :D
– Adam Smith
Nov 12 at 0:52
add a comment |
Since the problem space is so small, it's probably not a terrible idea to just generate three of them that are guaranteed unique.
valid_locations = (tup for tup in itertools.product(range(5), repeat=2) if tup != (0, 0))
items = ["S", "R", "*"]
choices = [(random.choice(items), loc) for loc in random.sample(valid_locations, 3)]
for item, (x, y) in choices:
twoDimMap[y][x] = item
random.sample(collection, n)
guarantees n
non-duplicated random results from collection
. random.choice(collection)
gives you a random element from collection
.
I was thinking similarly but you don't needitertools.product
here... I think you should be able to jump straight to:choices = ((random.choice(items), divmod(pos, 5)) for pos in random.sample(range(1, 25), 5))
...
– Jon Clements♦
Nov 12 at 0:47
@JonClements true, and great work avoiding the(0, 0)
with that, but it's obviously a bit more of a logical leap to see that.
– Adam Smith
Nov 12 at 0:48
1
Yeah... and if the H isn't going to be the first or last - it's doesn't work... but...
– Jon Clements♦
Nov 12 at 0:49
@JonClements but it's super neat :D
– Adam Smith
Nov 12 at 0:52
add a comment |
Since the problem space is so small, it's probably not a terrible idea to just generate three of them that are guaranteed unique.
valid_locations = (tup for tup in itertools.product(range(5), repeat=2) if tup != (0, 0))
items = ["S", "R", "*"]
choices = [(random.choice(items), loc) for loc in random.sample(valid_locations, 3)]
for item, (x, y) in choices:
twoDimMap[y][x] = item
random.sample(collection, n)
guarantees n
non-duplicated random results from collection
. random.choice(collection)
gives you a random element from collection
.
Since the problem space is so small, it's probably not a terrible idea to just generate three of them that are guaranteed unique.
valid_locations = (tup for tup in itertools.product(range(5), repeat=2) if tup != (0, 0))
items = ["S", "R", "*"]
choices = [(random.choice(items), loc) for loc in random.sample(valid_locations, 3)]
for item, (x, y) in choices:
twoDimMap[y][x] = item
random.sample(collection, n)
guarantees n
non-duplicated random results from collection
. random.choice(collection)
gives you a random element from collection
.
answered Nov 12 at 0:36
Adam Smith
33.1k53174
33.1k53174
I was thinking similarly but you don't needitertools.product
here... I think you should be able to jump straight to:choices = ((random.choice(items), divmod(pos, 5)) for pos in random.sample(range(1, 25), 5))
...
– Jon Clements♦
Nov 12 at 0:47
@JonClements true, and great work avoiding the(0, 0)
with that, but it's obviously a bit more of a logical leap to see that.
– Adam Smith
Nov 12 at 0:48
1
Yeah... and if the H isn't going to be the first or last - it's doesn't work... but...
– Jon Clements♦
Nov 12 at 0:49
@JonClements but it's super neat :D
– Adam Smith
Nov 12 at 0:52
add a comment |
I was thinking similarly but you don't needitertools.product
here... I think you should be able to jump straight to:choices = ((random.choice(items), divmod(pos, 5)) for pos in random.sample(range(1, 25), 5))
...
– Jon Clements♦
Nov 12 at 0:47
@JonClements true, and great work avoiding the(0, 0)
with that, but it's obviously a bit more of a logical leap to see that.
– Adam Smith
Nov 12 at 0:48
1
Yeah... and if the H isn't going to be the first or last - it's doesn't work... but...
– Jon Clements♦
Nov 12 at 0:49
@JonClements but it's super neat :D
– Adam Smith
Nov 12 at 0:52
I was thinking similarly but you don't need
itertools.product
here... I think you should be able to jump straight to: choices = ((random.choice(items), divmod(pos, 5)) for pos in random.sample(range(1, 25), 5))
...– Jon Clements♦
Nov 12 at 0:47
I was thinking similarly but you don't need
itertools.product
here... I think you should be able to jump straight to: choices = ((random.choice(items), divmod(pos, 5)) for pos in random.sample(range(1, 25), 5))
...– Jon Clements♦
Nov 12 at 0:47
@JonClements true, and great work avoiding the
(0, 0)
with that, but it's obviously a bit more of a logical leap to see that.– Adam Smith
Nov 12 at 0:48
@JonClements true, and great work avoiding the
(0, 0)
with that, but it's obviously a bit more of a logical leap to see that.– Adam Smith
Nov 12 at 0:48
1
1
Yeah... and if the H isn't going to be the first or last - it's doesn't work... but...
– Jon Clements♦
Nov 12 at 0:49
Yeah... and if the H isn't going to be the first or last - it's doesn't work... but...
– Jon Clements♦
Nov 12 at 0:49
@JonClements but it's super neat :D
– Adam Smith
Nov 12 at 0:52
@JonClements but it's super neat :D
– Adam Smith
Nov 12 at 0:52
add a comment |
Sometimes randrange(0, 5)
returns the same thing several times, thus some point is reassigned.
This could be solved by generating the coordinates together with the type and only executing the rest of the loop if that point is currently unoccupied. This would also eliminate the need for a separate (0,0) test-case.
While this answer is good, giving a way to solve it would be preferable.
– Olivier Melançon
Nov 12 at 0:25
Argh, of course. How did I forget about that :/
– Ch0w
Nov 12 at 0:26
add a comment |
Sometimes randrange(0, 5)
returns the same thing several times, thus some point is reassigned.
This could be solved by generating the coordinates together with the type and only executing the rest of the loop if that point is currently unoccupied. This would also eliminate the need for a separate (0,0) test-case.
While this answer is good, giving a way to solve it would be preferable.
– Olivier Melançon
Nov 12 at 0:25
Argh, of course. How did I forget about that :/
– Ch0w
Nov 12 at 0:26
add a comment |
Sometimes randrange(0, 5)
returns the same thing several times, thus some point is reassigned.
This could be solved by generating the coordinates together with the type and only executing the rest of the loop if that point is currently unoccupied. This would also eliminate the need for a separate (0,0) test-case.
Sometimes randrange(0, 5)
returns the same thing several times, thus some point is reassigned.
This could be solved by generating the coordinates together with the type and only executing the rest of the loop if that point is currently unoccupied. This would also eliminate the need for a separate (0,0) test-case.
edited Nov 12 at 0:27
answered Nov 12 at 0:24
MegaBluejay
33618
33618
While this answer is good, giving a way to solve it would be preferable.
– Olivier Melançon
Nov 12 at 0:25
Argh, of course. How did I forget about that :/
– Ch0w
Nov 12 at 0:26
add a comment |
While this answer is good, giving a way to solve it would be preferable.
– Olivier Melançon
Nov 12 at 0:25
Argh, of course. How did I forget about that :/
– Ch0w
Nov 12 at 0:26
While this answer is good, giving a way to solve it would be preferable.
– Olivier Melançon
Nov 12 at 0:25
While this answer is good, giving a way to solve it would be preferable.
– Olivier Melançon
Nov 12 at 0:25
Argh, of course. How did I forget about that :/
– Ch0w
Nov 12 at 0:26
Argh, of course. How did I forget about that :/
– Ch0w
Nov 12 at 0:26
add a comment |
To avoid overwriting previously placed items, you can use random.sample
, which will pick random items from the input sample without replacement.
There are several other convenient functions for sequences in the random
module.
I've rewritten your code and turned it into a function that can generate rectangular maps of any size and number and type of items.
import random
def make_map(width, height, number_of_items, items='SR*'):
"""Create a map with the Hero in top left corner
and random items spread around"""
# build an empty map using a nested list comprehension
game_map = [['-' for x in range(width)] for y in range(height)]
# place the hero at coordinates 0, 0
game_map[0][0] = 'H'
# possible item positions, excluding 0, where the hero is.
positions = range(1, width * height)
# loop over n random choices from the available positions
for pos in random.sample(positions, number_of_items):
# convert pos to x, y coordinates using modular arithmetic
x, y = pos % width, pos // width
# select a random item to and place it at coordinates x, y
game_map[y][x] = random.choice(items)
return game_map
# generate a map. You can change the input arguments to vary size and items
game_map = make_map(6, 6, 5)
# convert the nested list to one string and print
print('n'.join(''.join(line) for line in game_map))
We use modular arithmetic to convert the position value which is a number in the range 1 to 36 into x,y coordinates on a 6×6 grid. This is a very common and useful operation in computer graphics.
x, y = pos % width, pos // width
This is such a common operation that python has a built-in function you can use for this exact thing.
y, x = divmod(pos, width)
I will not explain all of the code, but I encourage you to read through the answers and try to understand how every line works. You can learn a lot from reading other people's solutions to the same problem as you have solved yourself.
add a comment |
To avoid overwriting previously placed items, you can use random.sample
, which will pick random items from the input sample without replacement.
There are several other convenient functions for sequences in the random
module.
I've rewritten your code and turned it into a function that can generate rectangular maps of any size and number and type of items.
import random
def make_map(width, height, number_of_items, items='SR*'):
"""Create a map with the Hero in top left corner
and random items spread around"""
# build an empty map using a nested list comprehension
game_map = [['-' for x in range(width)] for y in range(height)]
# place the hero at coordinates 0, 0
game_map[0][0] = 'H'
# possible item positions, excluding 0, where the hero is.
positions = range(1, width * height)
# loop over n random choices from the available positions
for pos in random.sample(positions, number_of_items):
# convert pos to x, y coordinates using modular arithmetic
x, y = pos % width, pos // width
# select a random item to and place it at coordinates x, y
game_map[y][x] = random.choice(items)
return game_map
# generate a map. You can change the input arguments to vary size and items
game_map = make_map(6, 6, 5)
# convert the nested list to one string and print
print('n'.join(''.join(line) for line in game_map))
We use modular arithmetic to convert the position value which is a number in the range 1 to 36 into x,y coordinates on a 6×6 grid. This is a very common and useful operation in computer graphics.
x, y = pos % width, pos // width
This is such a common operation that python has a built-in function you can use for this exact thing.
y, x = divmod(pos, width)
I will not explain all of the code, but I encourage you to read through the answers and try to understand how every line works. You can learn a lot from reading other people's solutions to the same problem as you have solved yourself.
add a comment |
To avoid overwriting previously placed items, you can use random.sample
, which will pick random items from the input sample without replacement.
There are several other convenient functions for sequences in the random
module.
I've rewritten your code and turned it into a function that can generate rectangular maps of any size and number and type of items.
import random
def make_map(width, height, number_of_items, items='SR*'):
"""Create a map with the Hero in top left corner
and random items spread around"""
# build an empty map using a nested list comprehension
game_map = [['-' for x in range(width)] for y in range(height)]
# place the hero at coordinates 0, 0
game_map[0][0] = 'H'
# possible item positions, excluding 0, where the hero is.
positions = range(1, width * height)
# loop over n random choices from the available positions
for pos in random.sample(positions, number_of_items):
# convert pos to x, y coordinates using modular arithmetic
x, y = pos % width, pos // width
# select a random item to and place it at coordinates x, y
game_map[y][x] = random.choice(items)
return game_map
# generate a map. You can change the input arguments to vary size and items
game_map = make_map(6, 6, 5)
# convert the nested list to one string and print
print('n'.join(''.join(line) for line in game_map))
We use modular arithmetic to convert the position value which is a number in the range 1 to 36 into x,y coordinates on a 6×6 grid. This is a very common and useful operation in computer graphics.
x, y = pos % width, pos // width
This is such a common operation that python has a built-in function you can use for this exact thing.
y, x = divmod(pos, width)
I will not explain all of the code, but I encourage you to read through the answers and try to understand how every line works. You can learn a lot from reading other people's solutions to the same problem as you have solved yourself.
To avoid overwriting previously placed items, you can use random.sample
, which will pick random items from the input sample without replacement.
There are several other convenient functions for sequences in the random
module.
I've rewritten your code and turned it into a function that can generate rectangular maps of any size and number and type of items.
import random
def make_map(width, height, number_of_items, items='SR*'):
"""Create a map with the Hero in top left corner
and random items spread around"""
# build an empty map using a nested list comprehension
game_map = [['-' for x in range(width)] for y in range(height)]
# place the hero at coordinates 0, 0
game_map[0][0] = 'H'
# possible item positions, excluding 0, where the hero is.
positions = range(1, width * height)
# loop over n random choices from the available positions
for pos in random.sample(positions, number_of_items):
# convert pos to x, y coordinates using modular arithmetic
x, y = pos % width, pos // width
# select a random item to and place it at coordinates x, y
game_map[y][x] = random.choice(items)
return game_map
# generate a map. You can change the input arguments to vary size and items
game_map = make_map(6, 6, 5)
# convert the nested list to one string and print
print('n'.join(''.join(line) for line in game_map))
We use modular arithmetic to convert the position value which is a number in the range 1 to 36 into x,y coordinates on a 6×6 grid. This is a very common and useful operation in computer graphics.
x, y = pos % width, pos // width
This is such a common operation that python has a built-in function you can use for this exact thing.
y, x = divmod(pos, width)
I will not explain all of the code, but I encourage you to read through the answers and try to understand how every line works. You can learn a lot from reading other people's solutions to the same problem as you have solved yourself.
edited Nov 12 at 1:23
answered Nov 12 at 0:40
Håken Lid
10.5k62441
10.5k62441
add a comment |
add a comment |
Less items are generated because there are times where the same coordinates are generated again. One way to avoid this is to check if the location already has an item before assigning it. This way, you will solve the issue of replacing your hero too.
import random
twoDimMap = [["H","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"]]
items = 0
item_list = ['S', 'R', '*']
while items <= 4:
x = random.randrange(0,5)
y = random.randrange(0,5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = item_list[random.randrange(0,3)]
items += 1
add a comment |
Less items are generated because there are times where the same coordinates are generated again. One way to avoid this is to check if the location already has an item before assigning it. This way, you will solve the issue of replacing your hero too.
import random
twoDimMap = [["H","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"]]
items = 0
item_list = ['S', 'R', '*']
while items <= 4:
x = random.randrange(0,5)
y = random.randrange(0,5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = item_list[random.randrange(0,3)]
items += 1
add a comment |
Less items are generated because there are times where the same coordinates are generated again. One way to avoid this is to check if the location already has an item before assigning it. This way, you will solve the issue of replacing your hero too.
import random
twoDimMap = [["H","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"]]
items = 0
item_list = ['S', 'R', '*']
while items <= 4:
x = random.randrange(0,5)
y = random.randrange(0,5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = item_list[random.randrange(0,3)]
items += 1
Less items are generated because there are times where the same coordinates are generated again. One way to avoid this is to check if the location already has an item before assigning it. This way, you will solve the issue of replacing your hero too.
import random
twoDimMap = [["H","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"],["-","-","-","-","-","-"]]
items = 0
item_list = ['S', 'R', '*']
while items <= 4:
x = random.randrange(0,5)
y = random.randrange(0,5)
if twoDimMap[x][y] == '-':
twoDimMap[x][y] = item_list[random.randrange(0,3)]
items += 1
answered Nov 12 at 0:33
boonwj
2169
2169
add a comment |
add a comment |
If your map isn't too big, you could use random.sample
to Choose at random from combinations.
twoDimMap = [list(line) for line in """
H-----
------
------
------
------
------""".split("n")]
width, height = len(twoDimMap[0]), len(twoDimMap)
allLocations = [(x, y) for x in range(width) for y in range(height) if (x, y) != (0, 0)]
for x, y in random.sample(allLocations, 5):
case = random.randrange(3)
twoDimMap[y][x] = "SR*"[case]
add a comment |
If your map isn't too big, you could use random.sample
to Choose at random from combinations.
twoDimMap = [list(line) for line in """
H-----
------
------
------
------
------""".split("n")]
width, height = len(twoDimMap[0]), len(twoDimMap)
allLocations = [(x, y) for x in range(width) for y in range(height) if (x, y) != (0, 0)]
for x, y in random.sample(allLocations, 5):
case = random.randrange(3)
twoDimMap[y][x] = "SR*"[case]
add a comment |
If your map isn't too big, you could use random.sample
to Choose at random from combinations.
twoDimMap = [list(line) for line in """
H-----
------
------
------
------
------""".split("n")]
width, height = len(twoDimMap[0]), len(twoDimMap)
allLocations = [(x, y) for x in range(width) for y in range(height) if (x, y) != (0, 0)]
for x, y in random.sample(allLocations, 5):
case = random.randrange(3)
twoDimMap[y][x] = "SR*"[case]
If your map isn't too big, you could use random.sample
to Choose at random from combinations.
twoDimMap = [list(line) for line in """
H-----
------
------
------
------
------""".split("n")]
width, height = len(twoDimMap[0]), len(twoDimMap)
allLocations = [(x, y) for x in range(width) for y in range(height) if (x, y) != (0, 0)]
for x, y in random.sample(allLocations, 5):
case = random.randrange(3)
twoDimMap[y][x] = "SR*"[case]
edited Nov 12 at 0:53
answered Nov 12 at 0:44
loxaxs
401517
401517
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53254564%2ftrying-to-generate-5-random-items-sometimes-generate-4%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
What do you mean by "generating fewer items than other times"?
– Jon Clements♦
Nov 12 at 0:22
I need to place 5 items in the list twoDimMap, an example of an instance wherein fewer items were placed is this: [['H', '-', 'S', '-', '-', '-'], ['-', '-', '-', '-', '-', '-'], ['', '-', '-', '-', '', '-'], ['-', '-', '-', '-', '-', '-'], ['S', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-']]
– Ch0w
Nov 12 at 0:23
Do not try to explain more in a comment. You can always edit your post, you know.
– usr2564301
Nov 12 at 0:24
4
This is probably caused by randomly getting the same x, y coordinates more than once.
– Håken Lid
Nov 12 at 0:24
1
I bet you generate 5 but one overwrites an earlier. So test if the contents of your new item are
-
first.– usr2564301
Nov 12 at 0:24