0
def dealHand(n):
    """
    Returns a random hand containing n lowercase letters.
    At least n/3 the letters in the hand should be VOWELS.

    Hands are represented as dictionaries. The keys are
    letters and the values are the number of times the
    particular letter is repeated in that hand.

    n: int >= 0
    returns: dictionary (string -> int)
    """

    hand={}
    numVowels = n / 3

    for i in range(numVowels):
        x = VOWELS[random.randrange(0, len(VOWELS))]
        hand[x] = hand.get(x, 0) + 1

    for i in range(numVowels, n):
        x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
        hand[x] = hand.get(x, 0) + 1

    return hand

This function is part of a word game I had to make, it was included in some helper functions to help get started, my problem is that the letters it returns are not very random, there are a lot of repeated letters like: a a c c b e e g j j m m m o o r t v y x, I am just wondering if it is possible to get a more random set of chars?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321

3 Answers3

1

"letters it returns are not very random, there are a lot of repeated letters " - seriously?

If you want to get n letters without repeats, use something like this:

from random import shuffle
alphabet = ['a', .., 'z']
shuffle(alphabet)
print(alphabet[:n])

if n > len(alphabet), you get repeats anyway.

gukoff
  • 2,112
  • 3
  • 18
  • 30
1

Here is a more compact representation of your algorithm:

from __future__ import division
from collections import Counter
import random
import string

VOWELS = "aeiou"
CONSONANTS = "".join(set(string.lowercase) - set(VOWELS))

def dealHand(n):
    numVowels = n // 3
    lettersets = [VOWELS] * numVowels + [CONSONANTS] * (n - numVowels)
    return Counter(c
        for letterset in lettersets
        for c in random.choice(letterset)
    )

Seems random enough.


And later: " if I wanted letters to appear no more than twice, how could I achieve that?"

Well, you could do this, but I am not recommending this:

def dealHand2(n):
    while True:
        candidate = dealHand(n)
        if all(v <= 2 for v in candidate.values()):
            return candidate

This is an infinite loop until it finds a set of letters that satisfies your condition. Running time: uncertain.

hughdbrown
  • 47,733
  • 20
  • 85
  • 108
  • Thanks, that seems to be giving a better selection, if I wanted letters to appear no more than twice, how could I achieve that? – Padraic Cunningham Mar 20 '13 at 18:16
  • Thanks, I really was just trying to find a way to make the game easier or harder based on how the hands are dealt. I am sure there are better ways but I have just started programming so this is about as technical as I can get so far, I will mark your first answer as the best as it solved my original issue, thanks again for the input – Padraic Cunningham Mar 20 '13 at 18:41
0

In this version you should have statistically three times more vowels than consonants, but the exact number is not guaranteed.

import collections
import random

VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'

def dealHand(n):
 letters = 3 * VOWELS + CONSONANTS 
 collections.Counter(random.sample(letters, n))
Charles
  • 733
  • 3
  • 7
  • 19
  • Re: " three times more vowels than consonants". Why would you have three times more vowels than consonants? There are 15 vowels and 21 consonants in your string. – hughdbrown Mar 20 '13 at 18:22