1
# Written by Bram Cohen
2
# see LICENSE.txt for license information
4
from random import randrange, shuffle, choice
7
def __init__(self, numpieces, rarest_first_cutoff = 1):
8
self.rarest_first_cutoff = rarest_first_cutoff
9
self.numpieces = numpieces
10
self.interests = [range(numpieces)]
11
self.pos_in_interests = range(numpieces)
12
self.numinterests = [0] * numpieces
16
self.scrambled = range(numpieces)
17
shuffle(self.scrambled)
19
def got_have(self, piece):
20
if self.numinterests[piece] is None:
22
numint = self.numinterests[piece]
23
if numint == len(self.interests) - 1:
24
self.interests.append([])
25
self.numinterests[piece] += 1
26
self._shift_over(piece, self.interests[numint], self.interests[numint + 1])
28
def lost_have(self, piece):
29
if self.numinterests[piece] is None:
31
numint = self.numinterests[piece]
32
self.numinterests[piece] -= 1
33
self._shift_over(piece, self.interests[numint], self.interests[numint - 1])
35
def _shift_over(self, piece, l1, l2):
36
p = self.pos_in_interests[piece]
38
self.pos_in_interests[l1[-1]] = p
40
newp = randrange(len(l2) + 1)
42
self.pos_in_interests[piece] = len(l2)
46
self.pos_in_interests[old] = len(l2)
49
self.pos_in_interests[piece] = newp
51
def requested(self, piece, seed = False):
52
if piece not in self.started:
53
self.started.append(piece)
54
if seed and piece not in self.seedstarted:
55
self.seedstarted.append(piece)
57
def complete(self, piece):
58
assert self.numinterests[piece] is not None
60
l = self.interests[self.numinterests[piece]]
61
p = self.pos_in_interests[piece]
63
self.pos_in_interests[l[-1]] = p
65
self.numinterests[piece] = None
67
self.started.remove(piece)
68
self.seedstarted.remove(piece)
72
def next(self, havefunc, seed = False):
81
if self.numinterests[i] < bestnum:
83
bestnum = self.numinterests[i]
84
elif self.numinterests[i] == bestnum:
88
if self.numgot < self.rarest_first_cutoff:
89
for i in self.scrambled:
93
for i in xrange(1, min(bestnum, len(self.interests))):
94
for j in self.interests[i]:
99
def am_I_complete(self):
100
return self.numgot == self.numpieces
102
def bump(self, piece):
103
l = self.interests[self.numinterests[piece]]
104
pos = self.pos_in_interests[piece]
107
for i in range(pos,len(l)):
108
self.pos_in_interests[l[i]] = i
110
def test_requested():
123
assert v[:2] == [1, 3] or v[:2] == [3, 1]
124
assert v[2:4] == [0, 6] or v[2:4] == [6, 0]
125
assert v[4:] == [2, 4] or v[4:] == [4, 2]
127
def test_change_interest():
137
assert v == [0, 4] or v == [4, 0]
139
def test_change_interest2():
149
assert v == [0, 4] or v == [4, 0]
155
assert _pull(p) == []
159
def test_rarer_in_started_takes_priority():
167
assert _pull(p) == [1, 0]
170
assert _pull(PiecePicker(0)) == []