Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hamish Campbell: Polyominoes - An Exploration in Problem Solving with Python

Hamish Campbell: Polyominoes - An Exploration in Problem Solving with Python

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Hamish Campbell:
Polyominoes - An Exploration in Problem Solving with Python
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
@ Kiwi PyCon 2013 - Saturday, 07 Sep 2013 - Track 2
http://nz.pycon.org/

**Audience level**

Intermediate

**Description**

A "Polyomino" is a geometric figure of adjacent squares. But just how many "n" polyominos are there? Solving this question is one of our favourite interview questions and the techniques that can employed to solve it are instructive for a range of problems. In this talk, we discuss the potential solutions and offer prizes for the best solutions submitted by the end of the conference.

**Abstract**

A "Polyomino" is a geometric figure of adjacent squares. But just how many "n" polyominos are there?

This question has been one of our favourite interview questions. It's a deceptively simple problem with opportunities for innovative solutions and disastrous missteps. In this talk, we'll discuss the benefits of a number of approaches, demonstrate a few common pitfalls and challenge the audience to provide their own solutions, with prizes on offer at the end of the conference.

This is a talk for everyone: beginners will be introduced to a problem that can be solved using primitives, experts will see opportunities to deploy advanced optimizations.

**YouTube**

http://www.youtube.com/watch?v=HXQW3MCOECU

New Zealand Python User Group

September 07, 2013
Tweet

More Decks by New Zealand Python User Group

Other Decks in Programming

Transcript

  1. Let's be specific Fixed Distinct when none is a translation

    of another... One-sided And none is a rotation of another... Free And none is a reflection / glide reflection of another.
  2. Define a Polyomino class Polyomino: def __init__(self, iterable): self.squares =

    tuple(iterable) p = Polyomino(((0,0), (0,1), (1,1)))
  3. Enumerating from Search Space n2 = 36 squares “From n

    choose r “ import gmpy gmpy.comb(36, 6) >> 1947792 GMPY: https://code.google.com/p/gmpy/ Multiple-precision arithmetic for Python
  4. Enumerating from Search Space 1 + (2 x 5) nCr

    6 + (3 x 4) nCr 6 1 + \ gmpy.comb(2*5, 6) +\ gmpy.comb(3*4, 6) >> 1135
  5. Enumeration def count_enumerations(d): import gmpy return 1 + sum( gmpy.comb(i

    * (1 + d ­ i), d) for i in range(1 + d // 2, d) )
  6. Enumeration for i in range(5, 10): print i, count_enumerations(i) 5

    183 6 1,135 7 18,668 8 172,732 9 3,655,850
  7. Building from Lower Order (n = 3) (n - 2)

    x 4 x (n -1) x 4 n = 4 (n – 3) x 4 x (n – 2) x 4 x (n – 1) x 4
  8. Building from Lower Order Assumes 4 edges! In reality we

    can pick a lower number, e.g. 1 import math for i in range(5, 10): print i, math.factorial(i) 5 120 8 40,320 6 720 9 362,880 7 5,040
  9. Identifying a Polyomino But remember the rules def __hash__(self): p

    = self, k = self.key() for _ in range(3): p = self.rotate().translate() k = min(k, p.key()) return k def key(self): return hash(self.squares)
  10. Using the set helpers How does the set `in` operator

    work? hash(a) == hash(b) and (a is b or id(a) == id(b))
  11. Challenges 1. Fastest 2. Lowest memory usage 3. Most esoteric,

    obfuscated or shortest solution See us at the Treehouse, 11am - 1pm Sunday ThinkGeek vouchers and spot prizes Reference implementation: http://bit.ly/1enn1ny (numpy arrays? pypy vs others? threading?)
  12. import sys, itertools class Polyomino(tuple): def __hash__(_):return(getattr(_,'',''))or[setattr(_,'',setattr(_,'_',map(min,zip( *(setattr(_,'p',_.__class__((c[1],m­c[0]­1)for(c)in(_.p))if'p'in(_.__dict__)else(_)) or(getattr(_,'p'))))))or(min(getattr(_,'',hash(tuple(sorted(setattr(_,'p',_.__class__( [(x­_._[0],y­_._[1])for(x,y)in(_.p)])if(_._[0]or(_._[1]))else(_.p))or(_.p))))),

    hash(tuple(sorted(_.p))))))for(m)in(itertools.repeat(max(max(_,key=max)),4))]and(getattr(_,'')) def __eq__(*_):return(1&len(set(map(hash,_)))) def __call__(_,__):return[_.__class__(((__,__),))]if(not(1%__))else(set(itertools.chain(*[set([_.__class__ (_+tuple([a]))for(a)in(set((c[0]+x,c[1]+y)for(c,(x,y))in(itertools.product( _,((­1,0),(1,0),(0,­1),(0,1)))))).difference(_)])for(_)in(_(__­1))]))) print(len(Polyomino()(int(sys.argv.pop())))) Thanks for listening @polemic [email protected]