The Movie Club 3.0

  1. Twelve Monkeys – arakyd

Previously on Movie Club

  1. Yin Shi Nan Nu (aka Eat Drink Man Woman) – Rimbo
  2. The Quiet Earth – XtienMurawski
  3. Carriers – TomChick
  4. Internal Affairs – Equis
  5. Oasis – Kyle Wilson
  6. Tromeo and Juliet – Talisker
  7. Seven Samurai – russellmz00
  8. Fresh – Tman

(I got too lazy re: the imdb/netflix links, etc, you’ll have to look 'em up yourself henceforth :)

I N 22. The Return of the Pink Panther (1975) – Houngan
I N 21. Trouble Every Day (2001) – Kelly Wand
I N 20. American Splendor (2003) – Jon_Danger
I N 19. Brotherhood of the Wolf (2001) – Jasper
I N 18. Aguirre: The Wrath of God (1972) – Drastic
I N 17. Nine Queens (2000) – malkav11
I N 16. Singin’ in the Rain (1952) – madkevin
I N 15. Gangster No. 1 (2000) – BlueJackalope
I N 14. Whisper of the Heart (1995) – Ben Sones
I N 13. Out of the Past (1947) – Andrew Mayer
I N 12. Jaws (1975) – Joe O’Malley
I N 11. Night of the Hunter (1955) – madkevin
I N 10. Becket (1964) – Gordon Cameron
I n 9. The Three Musketeers (1973) – Rimbo
I N 8. Butch Cassidy and the Sundance Kid (1969) – Bullhajj
I N 7. Wonder Boys (2000) – tromik
I N 6. Swing Kids (1993) – Wholly Schmidt
I N 5. Amistad (1997) – Hanzii
I N 4. The Quiet Man (1952) – VegasRobb
I N 3. After Life (1998) – Mordrak
I n 2. A Midnight Clear (1992) – Bill Dungsroman
I N 1. Sorcerer (1977) – TomChick

I = imdb; N = netflix (N instant watch, n not available)

The Selection System

We are now employing the services of the MovieSelectron 5000™, which measures participation in previous discussion threads and makes a random selection based on weighted participation scores (see followup post for explanation).

Procedure

The next movie picker will be chosen every two weeks; the picker will be notified via PM, as well as posted in this thread. Once notified, the selection should be posted as soon as is feasible – take enough time to put some thought into it, but don’t agonize about it for too long :)

Note: if your selection isn’t available via Netflix, don’t expect much discussion (OTOH, if it’s available for instant streaming, you’ll get a lot more takers).

There’s no set discussion period; once the next selection is posted, have at it, for as long as there’s interesting stuff to say. Revisiting older Movie Club selections is strongly encouraged – if you missed an earlier one, well, go watch it, and let us know what you think!

Movie discussion threads should be posted in the same manner as in previous weeks (see above threads for reference). Include IMDB, Netflix, and any other pertinent links in the initial post, along with whatever brief non-spoiler background/introduction you deem appropriate. A link back to the main Movie Club thread (this one) would be good too :)

Finally, as always, the two primary rules:

  1. No complaining about the picks, even if someone picks Battlefield Earth. If you hate the movie and can’t stand to discuss it, take a pass until next time.

  2. Be familiar with the movie before posting in the thread. IE, if you’ve never seen it, watch it before posting. If it’s a personal favorite that you’ve watched 132 times, cool. If you watched it a couple weeks ago, that’s cool to. If you saw half of it on cable back in '91, uh, go watch it again before posting.

Finally finally, thanks again to Kareem to getting the whole Movie Club ball rolling in the first place :)

Here’s how the selection script does its weightings:

  1. It doesn’t care how many posts you make in a thread; either you participated in that discussion, or you didn’t.

  2. “Quality” of posts is irrelevant, as that would be a total pain in the neck to try and judge, or worse, keep track of.

  3. Recent movie discussions are weighted more heavily than old ones (recent == the last eight or so).

  4. A bonus based on the number of discussions you’ve participated in is also applied.

  5. A penalty is applied to previous pickers.

The overall goal: While everyone who has ever participated is in the pool, it’s weighted towards the people who’ve participated regularly and/or recently (but haven’t yet been selected to make a pick).

Additionally, taking participation in older threads into account might encourage people to go back and watch ones from weeks they missed.

Here’s the selection table for Movie Club #18, f’rinstance:

pct %   poster                picked  participated
------  --------------------  ------  ------------------------
17.55%  Drastic                       1,2,3,4,5,6,7,8,10,11,12,13,14,15,16,17
 8.67%  snowcrash22                   1,2,10,11,13,14,15,17
 7.82%  Talisker                      9,10,11,12,13,15,16
 6.71%  russellmz00                   1,5,7,10,12,13,14,17
 5.47%  Jasper                        8,9,13,14,15,17
 5.04%  Jon_Danger                    1,11,16,17
 4.95%  Funkman                       1,2,4,7,16,17
 3.78%  Kyle Wilson                   1,3,4,6,9,11,13,15
 3.13%  Jeff Fries                    1,4,9,13,16
 2.87%  malkav11              17      1,2,3,12,13,14,15,16
 2.78%  Houngan                       2,8,9,11,16
 1.96%  Wisbechlad                    10,12,15
 1.82%  Rimbo                 9       1,2,3,4,5,6,7,8,12,13,16
 1.50%  Scourge                       1,2,3,4,6,11,13
 1.37%  quatoria                      12,17
 1.19%  jeff lackey                   16
 1.19%  extarbags                     16
 1.19%  XtienMurawski                 17
 1.19%  Troy S Goodfellow             16
 1.19%  Khelavaster                   17
 1.19%  Jason Levine                  16
 1.19%  Eric P                        16
 1.19%  Bill                          16
 1.19%  Aristophan                    16
 1.00%  MikeP                         2,6,14
 1.00%  Gordon Cameron        10      8,11,12,16
 0.98%  Tmanpdx                       1,2,3,4,5,6,7,10,11
 0.91%  TomChick              1       2,3,12,17
 0.74%  robsam                        15
 0.74%  BlueJackalope         15      1,10,11,12,13,14
 0.63%  Omniscia                      12,14
 0.59%  madkevin              11,16   1,2,3,4,7,8,9,10,12,13,14,15
 0.48%  Pogue Mahone                  1,9,12
 0.46%  MattKeil                      14
 0.46%  GregB                         14
 0.35%  John Merva                    3,9,11
 0.33%  Malathor                      9,13
 0.26%  Hanzii                5       2,6,10,11,12
 0.22%  corsair                       9,12
 0.22%  Machfive                      1,2,3,4,5
 0.22%  Andrew Mayer          13      1,2,8,11,12
 0.17%  z22                           12
 0.17%  rasputin                      12
 0.17%  prolix                        12
 0.17%  Wallapuctus                   12
 0.17%  Wader                         12
 0.17%  Telefrog                      12
 0.17%  Rywill                        12
 0.17%  Nellie                        1,3,5,6
 0.17%  Jerry Sizzler                 12
 0.17%  Hawkeye Fierce                12
 0.17%  Chris                         12
 0.17%  Alan Au                       12
 0.13%  forgeforsaken                 1,2,3
 0.13%  Moggraider                    2,7,8
 0.13%  Joe O'Malley          12      4,8,10,11
 0.13%  Bullhajj              8       1,2,3,4,6,7,9
 0.09%  TheSelfishGene                1,10
 0.04%  roguefrog                     3,6
 0.04%  nixon66                       9
 0.04%  Wholly Schmidt        6       1,2,3,5,7
 0.04%  Tim James                     9
 0.04%  Tankero                       2,3
 0.04%  Preachy Preach                9
 0.04%  Justin Fletcher               9
 0.04%  JPR                           7,8
 0.04%  Equis                         2,7
 0.04%  Dean                          1,5
 0.04%  Cormac                        9
 0.04%  Ben Sones             14      12
 0.04%  Athryn                        9
 0.04%  AlanT                         9
 0.02%  tromik                7       11
 0.02%  shift6                        4
 0.02%  rrmorton                      1
 0.02%  mystery                       4
 0.02%  metta                         1
 0.02%  krise madsen                  8
 0.02%  krayzkrok                     7
 0.02%  graller                       2
 0.02%  davida                        1
 0.02%  dashingly                     7
 0.02%  bahimiron                     2
 0.02%  awdougherty                   2
 0.02%  VegasRobb             4       11
 0.02%  SwampIrish                    1
 0.02%  SteveS                        2
 0.02%  Sebmojo                       7
 0.02%  Rock8man                      1
 0.02%  Robert Sharp                  2
 0.02%  RickH                         6
 0.02%  Quitch                        8
 0.02%  Mordrak               3       1,2
 0.02%  Mike Cathcart                 1
 0.02%  Mark Asher                    1
 0.02%  Marcus                        2
 0.02%  Kunikos                       2
 0.02%  Kelly Wand                    1
 0.02%  Kareem                        2
 0.02%  Kalle                         6
 0.02%  KWhit                         1
 0.02%  Hugin                         1
 0.02%  EvilIdler                     1
 0.02%  Donald L.                     4
 0.02%  Desslock                      1
 0.02%  Dave47                        7
 0.02%  Damien Neil                   8
 0.02%  Coca Cola Zero                6
 0.02%  Chuck                         2
 0.02%  Brendan                       2
 0.02%  Bill Dungsroman       2       1
 0.02%  BennyProfane                  4
 0.02%  Arioch                        8
 0.02%  Anaxagoras                    1
 0.02%  Albert Woo                    3
 0.02%  Acoustic Rob                  8

Movie Club #18 will be chosen by: Drastic!

The next movie picker pick will be made two weekends hence (May 9 or 10).

Hah. Go figure. ;)

Also: boy, I sure thought I’d participated in one or two threads in the middle somewhere, but no, giant gap.

That is really frickin’ cool, Andrew.

Thank you thank you thank you thank you thank you.

This is super cool.

I like this little bit in particular:

Additionally, taking into account participation in older threads might encourage people to go back and watch ones from weeks they missed.

Inspired.

Really can’t thank you enough for volunteering and working this out.

-amanpour

Nicely done, and a definite step up from randomly picking from whoever watched 2 movies ago.

Excellent!

We should make “Let the right one in” kinda sorta the de facto Movie Club #17.5 if you ask me. Grandfather it in. :)

Indeed, thanks for keeping the Club alive.

I’ll post a pick later tonight, once I manage to get a mental coinflip to stop spinning.

sometimes a physical coinflip works in that regards

as does a d20

i never leave home without my polyhedral dice

Glad everyone likes the picking system (so far, at least). Didn’t take too long to get everything scripted up; from here on out, all I need to do is tell it the URL to the latest thread and re-run it – will take me all of a minute or so to determine the picker in future weeks.

I’ll go ahead and post that numbers table each time, just 'cause I figure there’s more than a few numbers nerds around here :)

Oh, and if anyone’s curious to see my crappy python code, shoot me a PM, and I’d be happy to email it to you.

WHOA!

I’ll bite. Show me your python!

No seriously, as a Python programmer I’m curious to see how you did it.

OK nerds, here’s the script. You’ll need BeautifulSoup before you can run it yourself.

I even went through and commented stuff, woo!

#!/usr/bin/env python

# list of movie pick threads, most recent first
THREADLIST = [
    (52136, 'Drastic'),
    (51312, 'malkav11'),
    (51011, 'madkevin'),
    (50602, 'BlueJackalope'),
    (50281, 'Ben Sones'),
    (49833, 'Andrew Mayer'),
    (49469, 'Joe O\'Malley'),
    (48977, 'madkevin'),
    (48704, 'Gordon Cameron'),
    (48266, 'Rimbo'),
    (47738, 'Bullhajj'),
    (47378, 'tromik'),
    (47037, 'Wholly Schmidt'),
    (46740, 'Hanzii'),
    (46369, 'VegasRobb'),
    (46044, 'Mordrak'),
    (45626, 'Bill Dungsroman'),
    (45437, 'TomChick'),
]

# fibonacci weightings for the most recent threads.  The first two (current and previous picks)
# are given the same weight, as things don't usually get rolling until the second week due to
# Netflix lag.  Older threads get a weight of 1.
WEIGHTS = (55, 55, 34, 21, 13, 8, 5, 3, 2)

# pickle file, used to store thread data so we don't have to hit QT3 every single
# time we run the script (faster, plus saves QT3 the extra traffic).
# ... run the script with a '-f' parameter to ignore the pickled data, and pull fresh from QT3
PICKLE_FILE = 'movieclub.pickle'

from BeautifulSoup import BeautifulSoup
from collections import defaultdict
import urllib2
import re
import random
import math
import pickle
import sys

_THREAD_URL = 'http://www.quartertothree.com/game-talk/showthread.php?t=%s&page=%s'

_PAGES_RE = r'Page 1 of (?P<pagecount>\d+)'
_PAGES_MATCH = re.compile(_PAGES_RE)

class Thread(object):
    def __init__(self, thread_id, picker, pick_num):
        self.thread_id = thread_id
        self.picker = picker
        self.pick_num = pick_num
        self.weight = 1

        self.posters = []

        # get the pagecount
        pagecount = 1
        soup = BeautifulSoup(urllib2.urlopen(_THREAD_URL % (self.thread_id, 1)))
        cells = soup.findAll('td', 'vbmenu_control')
        for td_str in [td.renderContents() for td in cells]:
            matches = _PAGES_MATCH.match(td_str)
            if matches:
                pagecount = int(matches.group('pagecount'))
                break
        # loop through pages, add usernames to posters list
        for page in xrange(pagecount):
            soup = BeautifulSoup(urllib2.urlopen(_THREAD_URL % (self.thread_id, page+1)))
            posts = soup.findAll('div', 'page')
            for post in posts:
                try:
                    username = post.find('a', 'bigusername').renderContents()
                except AttributeError:
                    continue
                self.posters.append(username)

    def __repr__(self):
        return '<Thread thread_id: %i, picker: %s, weight %i>' % (self.thread_id, self.picker, self.weight)

if __name__ == '__main__':
    # add a -f parameter to the command line to force script to pull all data fresh from QT3
    fetch_from_qt3 = False
    try:
        fetch_from_qt3 = (sys.argv[1] == '-f')
    except IndexError:
        pass
    
    # try to load pickled data rather than pulling from qt3
    if not fetch_from_qt3:
        try:
            threads = pickle.load(file(PICKLE_FILE))
        except IOError:
            fetch_from_qt3 = True
            
    # fetch the threads fresh from QT3 if needed
    if fetch_from_qt3:
        threads = []
        for thread_id,picker in THREADLIST:
            pick_num = len(THREADLIST) - THREADLIST.index((thread_id,picker))
            threads.append(Thread(thread_id, picker, pick_num))
        pickle.dump(threads,file(PICKLE_FILE,'w'))

    # assign weights to recent threads
    for idx in xrange(len(WEIGHTS)):
        threads[idx].weight = WEIGHTS[idx]
        
    # set up our poster_scores dict
    poster_scores = defaultdict(int)

    # loop through distinct set of poster_scores for each thread, add the thread's weight
    # to their score (unless they were the thread "owner")
    for thread in threads:
        for poster in set(thread.posters):
            if poster != thread.picker:
                poster_scores[poster] += thread.weight

    # adjust previous picker's scores down (divide score by 3 for each previous pick)
    for thread in threads:
        poster_scores[thread.picker] /= 3

    # adjust up for overall participation: score = score * sqrt(num_of_threads_posted_in)
    # ... not counting threads where the poster was the picker
    for poster in poster_scores:
        threadcount = 0
        for thread in threads:
            if (poster in thread.posters) and (poster != thread.picker):
                threadcount += 1
        poster_scores[poster] *= int(math.sqrt(threadcount)+0.5)
    
    # make sure everybody's score is at least 1 (it's possible to hit zero otherwise)
    for poster in [p for p in poster_scores if poster_scores[p] == 0]:
        poster_scores[poster] = 1

    # choose the next picker
    pool = []
    for poster,score in poster_scores.items():
        pool.extend([poster] * score)
    next_picker = random.choice(pool)

    # print out the "selection table"
    print 'pct %   poster             picked  participated'
    print '------  -----------------  ------  -------------------------------'
    scores = [(value, key) for (key, value) in poster_scores.items()]
    scores.sort(reverse=True)
    total = sum(poster_scores.values())
    for score,name in scores:
        try:
            pct = 100.0*score/total
        except ZeroDivisionError:
            pct = 0
        p_threads = []
        p_picks = []
        for thread in threads:
            if (name in thread.posters) and (name != thread.picker):
                p_threads.append(thread.pick_num)
            elif name == thread.picker:
                p_picks.append(thread.pick_num)
        p_threads = [str(t) for t in sorted(p_threads)]
        p_picks = [str(p) for p in sorted(p_picks)]
        print '%5.2f%%  %-17s  %-6s  %s' % (pct, name, ','.join(p_picks), ','.join(p_threads))
    print

    # finally, print out the next picker
    print 'The next picker:  %s' % next_picker

Interesting, thanks. I’d never heard of Beautiful Soup.

Yep, that’s the only real interesting bit in there. Absolutely awesome tool, though.

Are you generating the “now playing” up at the top? If not, that seems… script-able.

Probably, but it’d take longer to script than it takes to do :)

only the first couple of times… amortized over time it might pay off :)