28 November 2007

Just for fun: jumbled to un-jumbled

Just for fun:
>>> jumble('Now is the Time for all Good Men to come to the aid of their Country...',0)
Now is the Time for all Good Men to come to the aid of their Country... 
-----------------------------------------------------------------------
Noo rf rot Thai wmr dda Guot Mct tf iehe hi tyo ino eo eloes Ceotnml...
Noo rf rot Thai wmr dda Guot Mct tf iehe ho tyo ino eo eloes Ceitnml...
Noo rf rot Thai wmr dda Guot Mct hf iehe to tyo ino eo eloes Ceitnml...
Noo rf rot Tiah wmr dda Guot Mct hf iehe to tyo ino eo eloes Ceitnml...
Noo rf rot Tiah wmr dda Guot Mct hf iehe to tyo ino eo eloes Ceitnml...
Noo rf rot Tiih wmr dda Guot Mct hf iehe to tyo ano eo eloes Ceitnml...
Noo rs rot Tiih wmr dda Guot Mct hf iehe to tyo ano eo eloef Ceitnml...
Noo rs rot Timh wmr dda Guot Mct hf iehe to tyo ano eo eloef Ceitnil...
Noo rs rot Timh wmr dda Guot Mct hf iehe to tyo ano eo eloef Ceitnil...
Noo rs rot Timh wmr add Guot Mct hf iehe to tyo ano eo eloef Ceitnil...
Noo is rot Timh wmr add Guot Mct hf iehe to tyo ano eo eloef Ceitnrl...
Noo is rot Timh wmr ado Guot Mct hf iehe to tyo and eo eloef Ceitnrl...
Noo is rot Timh wmr ado Guot Mct hf iehe to tyo and eo eloef Ceintrl...
Noo is rot Timh wmr ado Guot Mct hf nehe to tyo aid eo eloef Ceintrl...
Noo is rot Timh wmr ado Guot Mct hf nohe to tyo aid ee eloef Ceintrl...
Noo is rft Timh wmr ado Guot Mct ho nohe to tyo aid ee eloef Ceintrl...
Nou is rft Timh wmr ado Goot Mct ho nohe to tyo aid ee eloef Ceintrl...
Nou is rfe Timh wmr ado Goot Mct ho nohe to tyo aid ee tloef Ceintrl...
Nou is rfe Timh wmf ado Goot Mct ho nohe to tyo aid ee tloer Ceintrl...
Nou is rfe Timh wmf adl Goot Mct ho nohe to tyo aid ee tooer Ceintrl...
Nou is ree Timh wmf adl Goot Mct ho nohe to tyo aid ef tooer Ceintrl...
Nou is ree Timh wmf adl Goot Mct ho nohe to tyo aid of toeer Ceintrl...
Nou is ree Timh wmf adl Goot Mct ho nohe to tyo aid of toeer Ceintrl...
Nou is ree Timh wmf adl Goot Mct ho nohe to tyo aid of toeer Ceintrl...
Nou is ree Timh wmf adl Goot Mcn ho tohe to tyo aid of toeer Ceintrl...
Nou is ree Timh wmf adl Goot Mcn ho tohe to tyo aid of toeer Ceintrl...
Nou is ree Timh fmw adl Goot Mcn ho tohe to tyo aid of toeer Ceintrl...
Now is ree Timh fmu adl Goot Mcn ho tohe to tyo aid of toeer Ceintrl...
Now is ree Timh fmu adl Goot Mcn oo tohe to tyo aid of theer Ceintrl...
Now is ree Timh fmi adl Goot Mcn oo tohe to tyo aid of theer Ceuntrl...
Now is ree Timh fmi adl Goot Mcn oo tohe to tlo aid of theer Ceuntry...
Now is ree Timh fmi adl Goot Mcn oo tohe to tle aid of theer Country...
Now is ree Timh fhi adl Goot Mcn oo tome to tle aid of theer Country...
Now is ree Timh fli adl Goot Mcn oo tome to the aid of theer Country...
Now is rce Timh fli adl Goot Men oo tome to the aid of theer Country...
Now is rce Timh fli adl Goot Men oo tome to the aid of theer Country...
Now is rce Timh fli adl Goot Men oo tome to the aid of theer Country...
Now is rhe Timc fli adl Goot Men oo tome to the aid of theer Country...
Now is rhe Time fli adl Goot Men oo tome to the aid of thecr Country...
Now is rhe Time flc adl Goot Men oo tome to the aid of their Country...
Now is rhe Time flt adl Goot Men oo come to the aid of their Country...
Now is rhe Time flt atl Good Men oo come to the aid of their Country...
Now is the Time flr atl Good Men oo come to the aid of their Country...
Now is the Time flr aol Good Men to come to the aid of their Country...
Now is the Time for all Good Men to come to the aid of their Country...
Now is the Time for all Good Men to come to the aid of their Country...
Now is the Time for all Good Men to come to the aid of their Country...
Now is the Time for all Good Men to come to the aid of their Country...
Here is the code:
import random, string

class JumbledString(object):
    def __init__(self, original):
        self.original = list(original)
        self.remaining = list(original)
        # positions in self.jumbled that are
        # still available
        self.available = range(len(original))
        self.jumbled = self.jumble(original)

    # jumbling up all doesn't look too good.
    # let's try jumbling up only ascii lowercase.
    def jumble(self, st):
        tmp = []
        ins = []
        for (i, c) in enumerate(st):
            if c not in string.ascii_lowercase:
                self.available.remove(i)
                self.remaining.remove(c)
                ins.append((i, c))
            else:
                tmp.append(c)
        random.shuffle(tmp)
        for (i, c) in sorted(ins):
            tmp.insert(i, c)
        return tmp

    def is_done(self):
        return len(self.remaining) == 0

    def findall(self, char, string):
        res = [i for (i, c) in enumerate(string) if c == char]
        random.shuffle(res)
        return res

    def find_in_jumbled(self, char):
        res = [i
               for (i, c) in enumerate(self.jumbled)
               if c == char and i in self.available]
        assert res, "can't find char in find_in_jumbled!"
        random.shuffle(res)
        return res[0]

    def rand_swap(self):
        choice = random.choice(self.remaining)
        self.remaining.remove(choice)
        for pos in self.findall(choice, self.original):
            if pos in self.available:
                self.available.remove(pos)
                if self.jumbled[pos] == choice:
                    return pos, pos
                swappos = self.find_in_jumbled(choice)
                tmp = self.jumbled[pos]
                self.jumbled[pos] = choice
                self.jumbled[swappos] = tmp
                return pos, swappos
        assert False, "this can't happen in rand_swap!"

    def get_jumbled(self):
        return ''.join(self.jumbled)


def jumble(sentence, print_marker=True):
    print sentence, '\n', '-'*len(sentence)
    i = 1
    j = JumbledString(sentence)
    while not j.is_done():
        a, b = j.rand_swap()
        print j.get_jumbled()
        if print_marker:
            print marker(len(sentence), min(a, b), max(a, b))
        i += 1
        assert i < 2*len(sentence) # just for safety

def marker(slen, a, b):
    if a == b:
        return ' '*a + '^' + ' '*(slen-a-1)
    else:
        return ' '*a + '^' + '-'*(b-a-1) + '^' + ' '*(slen-b-1)