1

I am currently building a MUD (Multi-User-Domain) for an rpg game. Doing this entirely in Python to both make a game I enjoy, and learn python. A problem I am running in to, and due to the extreme specificity of the question, I've been unable to find the right answer.

So, here's what I need, in a nut-shell. I don't have a good snippet of code that fully shows what I need as I'd have to paste about 50 lines to have to 5 lines I'm using make sense.

targetOptions = ['Joe', 'Bob', 'zombie', 'Susan', 'kobold', 'Bill']

A cmd in our game is attack, where we type 'a zombie' and we then proceed to kill the zombie. However, I want to just type 'a z'. We've tried a few different things in our code, but they're all unstable and often just wrong. One of our attempts returned something like ['sword', 'talisman'] as matches for 'get sword'. So, is there a way to search this list and have it return a matched value?

I also need to just return value[0] if there are say, 2 zombies in the room and I type 'a z'. Thanks for all your help ahead of time, and I hope I was clear enough for what I'm looking for. Please let me know if more info is needed. And don't worry about the whole attacking thing, I just need to send 'zo' and get 'zombie' or something similar. Thanks!

jtsmith1287
  • 1,110
  • 2
  • 13
  • 24

2 Answers2

2

Welcome to SO and Python! I suggest you take a look at the official Python documentation and spend some time looking around what's included in the Python Standard Library.

The difflib module contains a function get_close_matches() that can help you with approximate string comparisons. Here's how it looks like:

from difflib import get_close_matches

def get_target_match(target, targets):
    '''
    Approximates a match for a target from a sequence of targets,
    if a match exists.
    '''
    source, targets = targets, map(str.lower, targets)
    target = target.lower()

    matches = get_close_matches(target, targets, n=1, cutoff=0.25)

    if matches:
        match = matches[0]
        return source[targets.index(match)]
    else:
        return None

target = 'Z'
targets = ['Joe', 'Bob', 'zombie', 'Susan', 'kobold', 'Bill']
match = get_target_match(target, targets)
print "Going nom on %s" % match # IT'S A ZOMBIE!!!
Filip Dupanović
  • 32,650
  • 13
  • 84
  • 114
  • edit: it appears to be, according to documentation examples, that this is for something along the lines of spelling correction. I can give appel and have apple returned. Z will not match zombie in this case. Anything less than 3 characters returns None as well. 'j' and 'jo' do not return 'Joe'. – jtsmith1287 Jul 05 '12 at 21:52
  • Forgot to adjust the cutoff, give it another try o/ – Filip Dupanović Jul 05 '12 at 21:54
0
>>> filter(lambda x: x.startswith("z"), ['Joe', 'Bob', 'zombie', 'Susan', 'kobold', 'Bill'])
['zombie']
>>> cmd = "a zom"
>>> cmd.split()
['a', 'zom']
>>> cmd.split()[1]
'zom'
>>> filter(lambda x: x.startswith(cmd.split()[1]), ['Joe', 'Bob', 'zombie', 'Susan', 'kobold', 'Bill'])
['zombie']

does that help?

filter filters a list (2nd arg) for things that the 1st arg accepts. cmd is your command and cmd.split()[1] gets the part after the space. lambda x: x.startswith(cmd.split()[1]) is a function (a lambda expression) that asks "does x start with the command after the space?"

for another test, if cmd is "a B" then there are two matches:

>>> cmd = "a B"
>>> filter(lambda x: x.startswith(cmd.split()[1]), ['Joe', 'Bob', 'zombie', 'Susan', 'kobold', 'Bill'])
['Bob', 'Bill']
andrew cooke
  • 45,717
  • 10
  • 93
  • 143