Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

import logging 

 

from django.db import models 

from django.core.urlresolvers import reverse_lazy 

from django.core.serializers import serialize 

from django.contrib.auth.models import User 

from django.utils.translation import ugettext_lazy as _ 

from django.template.defaultfilters import date, filesizeformat as fmt 

from django.conf import settings 

 

from tictactoe.tools.validators import ByteLengthValidator 

from tictactoe.tools.models import OwnManager 

 

from . import fixtures 

 

 

logger = logging.getLogger(__name__) 

 

 

class HandedOutCaps(models.Model): 

    user = models.ForeignKey(User) 

    when = models.DateTimeField(auto_now_add=True) 

    notes = models.CharField(max_length=255) 

 

    def __str__(self): 

        return "To %s at %s" % (self.user, date(self.when, "Y-m-d H:i:s")) 

 

    class Meta: 

        ordering = '-when', 

 

 

class Entry(models.Model): 

    _max_len = ByteLengthValidator(settings.MAX_CODE_SIZE) 

 

    user = models.ForeignKey(User) 

    code = models.TextField(validators=[_max_len]) 

 

    uploaded = models.DateTimeField(auto_now_add=True) 

    modified = models.DateTimeField(auto_now=True) 

 

    objects = models.Manager() 

    own = OwnManager('user') 

 

    @property 

    def codesize(self): 

        return len(self.code.encode('utf8')) 

 

    def get_absolute_url(self): 

        return reverse_lazy('tictactoe.contest.views.entry', args=[self.id]) 

 

    def __str__(self): 

        return "<Entry %d by %s (%s)>" % ( 

            self.id, self.user, fmt(self.codesize)) 

 

    def add_latest(self): 

        """After qualifying, make it LatestEntry of this user""" 

        latest = LatestEntry.objects.filter(user=self.user).first() 

        if latest is None: 

            LatestEntry(user=self.user, entry=self).save() 

        else: 

            latest.entry = self 

            latest.save() 

 

    def qualify(self): 

        """Scheulde a qualification with dumb_player and maybe go compete""" 

        from .tasks import schedule_qualification 

        logger.info("Scheduling %s for qualification" % self) 

        schedule_qualification.delay(serialize('json', [self])) 

 

    @staticmethod 

    def qualification_entry(): 

        u = User.objects.get(username='Qualification-Bot') 

        return Entry.objects.get(user=u) 

 

    class Meta: 

        verbose_name_plural = 'Entries' 

        ordering = '-uploaded', 

 

 

class LatestEntry(models.Model): 

    user = models.ForeignKey(User) 

    entry = models.ForeignKey(Entry) 

 

    def calc_results(self): 

        r1 = Fight.objects.filter( 

            x__latestentry=self, o__latestentry__isnull=False 

            ).values('result').annotate(cnt=models.Count('result')) 

        r2 = Fight.objects.filter( 

            o__latestentry=self, x__latestentry__isnull=False 

            ).values('result').annotate(cnt=models.Count('result')) 

        d1 = dict(((d['result'], d['cnt']) for d in r1)) 

        d2 = dict(((d['result'], d['cnt']) for d in r2)) 

        win = d1.get('win', 0) + d2.get('loss', 0) 

        draw = d1.get('draw', 0) + d2.get('draw', 0) 

        loss = d1.get('loss', 0) + d2.get('win', 0) 

        return win, draw, loss 

 

    def __str__(self): 

        return "<LatestEntry by %s>" % (self.user) 

 

    class Meta: 

        verbose_name_plural = 'Latest Entries' 

 

 

class Fight(models.Model): 

    """e1 is x, e2 is o. Results relative to e1. 

 

    Each Entry has two Fight objects: one with x, one with o""" 

 

    FIGHT_RESULT = ( 

        ('win', _('win')), 

        ('draw', _('draw')), 

        ('loss', _('loss')), 

    ) 

 

    created = models.DateTimeField(auto_now_add=True) 

    modified = models.DateTimeField(auto_now=True) 

    x = models.ForeignKey(Entry, related_name='e1') 

    o = models.ForeignKey(Entry, related_name='e2') 

 

    # len(",".join(map(str, range(1, 81)))) == 230 

    # Zero signifies error and in case of error is always the last number 

    gameplay = models.CommaSeparatedIntegerField( 

        max_length=230, 

        help_text=_( 

            "Gameplay flow. Board is separated to 81 cells. Each " 

            "number means a move by alternating player. For example, " 

            "'10,1,0' means: x placed (2,1,1,1), o placed (1,1,1,1) and " 

            "x made an error. In case 0 is at the end (like in the example), " 

            "'error' field is non-empty.") 

    ) 

 

    error = models.CharField( 

        max_length=255, blank=True, 

        help_text=_("Non-empty if `gameplay' ends with zero") 

    ) 

 

    result = models.CharField( 

        max_length=10, choices=FIGHT_RESULT, 

        help_text=_("Fight result of x (e1) versus o (e2). Relative to e1.") 

    ) 

 

    def result_of_x(self): 

        return self.result 

 

    def result_of_o(self): 

        if self.result == 'draw': 

            return 'draw' 

        return self.result == 'loss' and 'win' or 'win' 

 

    class Meta: 

        index_together = ( 

            ('x', 'result'), 

            ('o', 'result'), 

        ) 

        unique_together = ('x', 'o') 

 

    @staticmethod 

    def from_compete(x, o, round_result): 

        """Creates Fight instance from output of tictactoelib.compete""" 

        fight, _created = Fight.objects.get_or_create(x=x, o=o) 

        if round_result[0] == 'ok': 

            _, xodraw, gameplay = round_result 

            res = 'draw' 

            if xodraw == 'x' or xodraw == 'o': 

                res = xodraw == 'x' and 'win' or 'loss' 

            fight.gameplay = gameplay 

            fight.result = res 

            return fight 

        elif round_result[0] == 'error': 

            _, xo, reason, gameplay = round_result 

            res = 'win' if xo == 'o' else 'loss' 

            fight.gameplay = gameplay 

            fight.error = reason 

            fight.result = res 

            return fight 

 

    def get_absolute_url(self): 

        return reverse_lazy('tictactoe.contest.views.fight', args=[self.id]) 

 

    def __str__(self): 

        return "<Fight %s vs %s. Result: %s>" % (self.x, self.o, self.result) 

 

 

models.signals.post_migrate.connect(fixtures.qualification_bot)