Trying to generate 5 random items, sometimes generate 4












3














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.










share|improve this question




















  • 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
















3














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.










share|improve this question




















  • 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














3












3








3







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.










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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














  • 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












6 Answers
6






active

oldest

votes


















4














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





share|improve this answer



















  • 4




    Or unless something else is going to happen with those ifs... 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










  • Ahh... good point... Can still simplify the ifs 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



















3














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.






share|improve this answer





















  • 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






  • 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



















1














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.






share|improve this answer























  • 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



















1














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.






share|improve this answer































    0














    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





    share|improve this answer





























      0














      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]





      share|improve this answer























        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
        });


        }
        });














        draft saved

        draft discarded


















        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









        4














        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





        share|improve this answer



















        • 4




          Or unless something else is going to happen with those ifs... 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










        • Ahh... good point... Can still simplify the ifs 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
















        4














        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





        share|improve this answer



















        • 4




          Or unless something else is going to happen with those ifs... 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










        • Ahh... good point... Can still simplify the ifs 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














        4












        4








        4






        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





        share|improve this answer














        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






        share|improve this answer














        share|improve this answer



        share|improve this answer








        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 those ifs... 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










        • Ahh... good point... Can still simplify the ifs 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














        • 4




          Or unless something else is going to happen with those ifs... 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










        • Ahh... good point... Can still simplify the ifs 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








        4




        4




        Or unless something else is going to happen with those ifs... 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 ifs... 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 ifs 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 ifs 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













        3














        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.






        share|improve this answer





















        • 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






        • 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
















        3














        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.






        share|improve this answer





















        • 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






        • 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














        3












        3








        3






        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.






        share|improve this answer












        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 12 at 0:36









        Adam Smith

        33.1k53174




        33.1k53174












        • 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






        • 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










        • @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











        1














        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.






        share|improve this answer























        • 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
















        1














        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.






        share|improve this answer























        • 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














        1












        1








        1






        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.






        share|improve this answer














        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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        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


















        • 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











        1














        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.






        share|improve this answer




























          1














          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.






          share|improve this answer


























            1












            1








            1






            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.






            share|improve this answer














            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.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 12 at 1:23

























            answered Nov 12 at 0:40









            Håken Lid

            10.5k62441




            10.5k62441























                0














                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





                share|improve this answer


























                  0














                  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





                  share|improve this answer
























                    0












                    0








                    0






                    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





                    share|improve this answer












                    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






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 12 at 0:33









                    boonwj

                    2169




                    2169























                        0














                        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]





                        share|improve this answer




























                          0














                          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]





                          share|improve this answer


























                            0












                            0








                            0






                            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]





                            share|improve this answer














                            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]






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Nov 12 at 0:53

























                            answered Nov 12 at 0:44









                            loxaxs

                            401517




                            401517






























                                draft saved

                                draft discarded




















































                                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.




                                draft saved


                                draft discarded














                                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





















































                                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







                                Popular posts from this blog

                                Florida Star v. B. J. F.

                                Error while running script in elastic search , gateway timeout

                                Adding quotations to stringified JSON object values