Hide keyboard shortcuts

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# -*- coding: utf-8 -*- 

2from __future__ import annotations 

3 

4# -- stdlib -- 

5from itertools import chain, combinations as C, permutations as P 

6from typing import Any, cast 

7import logging 

8import random 

9 

10# -- third party -- 

11import gevent 

12 

13# -- own -- 

14from game.base import EventHandler 

15from thb.actions import ActionStageLaunchCard, CardChooser, skill_wrap, CharacterChooser 

16from thb.inputlets import ActionInputlet, ChooseOptionInputlet, ChoosePeerCardInputlet 

17 

18 

19# -- code -- 

20log = logging.getLogger('UserInputFuzzingHandler') 

21 

22 

23def let_it_go(*cores): 

24 while True: 

25 gevent.idle(-100) 

26 

27 for i in range(10): 27 ↛ 33line 27 didn't jump to line 33, because the loop on line 27 didn't complete

28 if any(c.server._ep.active for c in cores): 

29 break 

30 

31 gevent.sleep(0.05) 

32 else: 

33 raise Exception('STUCK!') 

34 

35 for c in cores: 

36 c.server._ep.active = False 

37 

38 

39class UserInputFuzzingHandler(EventHandler): 

40 

41 def handle(self, evt: str, arg: Any) -> Any: 

42 if evt == 'user_input': 

43 trans, ilet = arg 

44 self.react(trans, ilet) 

45 

46 return arg 

47 

48 def react(self, trans, ilet): 

49 p = ilet.actor 

50 g = self.game 

51 

52 if trans.name == 'ActionStageAction': 

53 if random.random() < 0.05: 

54 return False 

55 

56 cards = list(p.showncards) + list(p.cards) + list(p.equips) 

57 

58 while random.random() < 0.5: 

59 # Skill 

60 skl = [sk for sk in p.skills if sk.target.__name__ != 't_None'] 

61 if skl: 61 ↛ 64line 61 didn't jump to line 64, because the condition on line 61 was never false

62 sk = random.choice(skl) 

63 else: 

64 break 

65 

66 # Card 

67 cc = list(chain(*[C(cards, i) for i in range(4)])) 

68 random.shuffle(cc) 

69 

70 for cl in cc: 

71 for tl in self.possible_targets(g, p, sk): 

72 c = skill_wrap(p, [sk], cl, {}) 

73 

74 ok, reason = self.ui_meta_walk_wrapped([c]) 

75 if not ok: 75 ↛ 76line 75 didn't jump to line 76, because the condition on line 75 was never true

76 assert not c.check(), (c, c.associated_cards, c.check(), ok, reason) 

77 continue 

78 

79 try: 

80 tl, ok = c.target(p, tl) 

81 except Exception as e: 

82 raise Exception(f"{c}.target: {c.target} failed") from e 

83 

84 try: 

85 ok2, reason = c.ui_meta.is_action_valid(c, tl) 

86 except Exception as e: 

87 raise Exception(f"{c}.ui_meta.is_action_valid failed") from e 

88 

89 # This can happen 

90 # assert (ok and bool(c.check())) == ok2, { 

91 # 'ok': ok, 

92 # 'c.check()': c.check(), 

93 # 'ok2': ok2, 

94 # 'c': c, 

95 # 'tl': tl, 

96 # 'reason': reason, 

97 # } 

98 

99 if not ok: 

100 continue 

101 

102 if self.try_launch(ilet, cl, tl, skills=[sk]): 

103 return 

104 break 

105 

106 for c in cards: 

107 if not c.associated_action: 

108 continue 

109 

110 for t in self.possible_targets(g, p, c): 

111 if self.try_launch(ilet, [c], t): 

112 return True 

113 

114 elif trans.name in ('Action', 'AskForRejectAction') and isinstance(ilet, ActionInputlet): 

115 rst = { 

116 'skills': [], 

117 'cards': [], 

118 'characters': [], 

119 } 

120 

121 if ilet.categories: 

122 cond = cast(CardChooser, ilet.initiator).cond 

123 cl = list(p.showncards) + list(p.cards) 

124 

125 for skcls in ilet.actor.skills: 125 ↛ 137line 125 didn't jump to line 137, because the loop on line 125 didn't complete

126 if cond([skcls(ilet.actor)]) and random.random() < 0.5: 

127 for c in chain([], C(cl, 1), C(cl, 2), [cl]): 127 ↛ 134line 127 didn't jump to line 134, because the loop on line 127 didn't complete

128 sk = skill_wrap(p, [skcls], c, {}) 

129 assert cond([sk]) 

130 rst['skills'] = [skcls] 

131 rst['cards'] = c 

132 break 

133 

134 if rst: 134 ↛ 125line 134 didn't jump to line 125, because the condition on line 134 was never false

135 break 

136 else: 

137 for c in chain(C(cl, 1), C(cl, 2), [cl]): 

138 if cond(c): 

139 rst['cards'] = c 

140 break 

141 

142 if ilet.candidates: 

143 target = cast(CharacterChooser, ilet.initiator).choose_player_target 

144 # (self, pl: Sequence[Character]) -> Tuple[List[Character], bool]: ... 

145 pl = ilet.candidates 

146 for p in chain(C(pl, 1), C(pl, 2), [pl]): 146 ↛ 152line 146 didn't jump to line 152, because the loop on line 146 didn't complete

147 p, ok = target(p) 

148 if ok: 148 ↛ 146line 148 didn't jump to line 146, because the condition on line 148 was never false

149 rst['characters'] = p 

150 break 

151 

152 if rst: 152 ↛ 155line 152 didn't jump to line 155, because the condition on line 152 was never false

153 ilet.set_result(**rst) 

154 

155 return True 

156 

157 elif trans.name == 'ChooseOption' and isinstance(ilet, ChooseOptionInputlet): 

158 ilet.set_option(random.choice(list(ilet.options) * 2 + [None])) 

159 

160 elif trans.name == 'ChoosePeerCard' and isinstance(ilet, ChoosePeerCardInputlet): 

161 tgt = ilet.target 

162 if random.random() < 0.9: 

163 cats = [getattr(tgt, i) for i in ilet.categories] 

164 cl = list(chain(*cats)) 

165 if cl: 165 ↛ exitline 165 didn't return from function 'react', because the condition on line 165 was never false

166 ilet.set_card(random.choice(cl)) 

167 elif trans.name == 'SortCharacter': 167 ↛ 168line 167 didn't jump to line 168, because the condition on line 167 was never true

168 pass 

169 elif trans.name == 'ChooseGirl': 

170 from settings import TESTING_CHARACTERS as TESTS 

171 choices = [c for c in ilet.mapping[ilet.actor] if c.char_cls and c.char_cls.__name__ in TESTS] 

172 if choices: 172 ↛ 173line 172 didn't jump to line 173, because the condition on line 172 was never true

173 c = random.choice(choices) 

174 log.info('Got %s', c.char_cls) 

175 ilet.set_choice(c) 

176 elif trans.name == 'HarvestChoose': 

177 pass 

178 elif trans.name == 'Pindian': 

179 pass 

180 elif trans.name == 'HopeMask': 

181 pass 

182 elif trans.name == 'Prophet': 

183 pass 

184 elif trans.name == 'ChooseIndividualCard': 184 ↛ 185line 184 didn't jump to line 185, because the condition on line 184 was never true

185 pass 

186 elif trans.name == 'BanGirl': 186 ↛ 189line 186 didn't jump to line 189, because the condition on line 186 was never false

187 pass 

188 else: 

189 log.warning('Not processing %s transaction', trans.name) 

190 1/0 

191 

192 def ui_meta_walk_wrapped(self, cl, check_is_complete=False): 

193 from thb.cards.base import Skill 

194 for c in cl: 

195 if not isinstance(c, Skill): 

196 continue 

197 

198 if check_is_complete: 198 ↛ 199line 198 didn't jump to line 199, because the condition on line 198 was never true

199 rst, reason = c.ui_meta.is_complete(c) 

200 if not rst: 

201 return rst, reason 

202 

203 rst, reason = self.ui_meta_walk_wrapped(c.associated_cards, True) 

204 if not rst: 204 ↛ 205line 204 didn't jump to line 205, because the condition on line 204 was never true

205 return rst, reason 

206 

207 return True, 'OK' 

208 

209 def try_launch(self, ilet, cl, tl, skills=[]): 

210 p = ilet.actor 

211 if skills: 

212 c = skill_wrap(p, skills, cl, {}) 

213 else: 

214 assert len(cl) == 1, cl 

215 c, = cl 

216 

217 act = ActionStageLaunchCard(p, tl, c) 

218 if act.can_fire(): 

219 ilet.set_result(skills=skills, cards=cl, characters=tl) 

220 return True 

221 

222 return False 

223 

224 def possible_targets(self, g, me, c): 

225 target = c.target 

226 tn = target.__name__ 

227 pl = g.players 

228 

229 if tn == 't_None': 229 ↛ 230line 229 didn't jump to line 230, because the condition on line 229 was never true

230 raise Exception('Fuck') 

231 

232 elif tn == 't_Self': 232 ↛ 233line 232 didn't jump to line 233, because the condition on line 232 was never true

233 rl = [[me]] 

234 

235 elif tn == 't_OtherOne': 235 ↛ 236line 235 didn't jump to line 236, because the condition on line 235 was never true

236 rl = list(pl) 

237 random.shuffle(rl) 

238 rl = [[i] for i in rl if i is not me] 

239 

240 elif tn == 't_One': 240 ↛ 241line 240 didn't jump to line 241, because the condition on line 240 was never true

241 rl = list(pl) 

242 random.shuffle(rl) 

243 rl = [[i] for i in rl] 

244 

245 elif tn == 't_All': 245 ↛ 246line 245 didn't jump to line 246, because the condition on line 245 was never true

246 rl = list(pl) 

247 rl.remove(me) 

248 rl = [rl] 

249 

250 elif tn == 't_AllInclusive': 250 ↛ 251line 250 didn't jump to line 251, because the condition on line 250 was never true

251 rl = [pl] 

252 

253 elif tn == '_t_OtherLessEqThanN': 253 ↛ 254line 253 didn't jump to line 254, because the condition on line 253 was never true

254 n = target._for_test_OtherLessEqThanN 

255 rl = [] 

256 for i in range(n+1): 

257 rl.extend(list(P(pl, i))) 

258 random.shuffle(rl) 

259 

260 elif tn == 't_OneOrNone': 260 ↛ 261line 260 didn't jump to line 261, because the condition on line 260 was never true

261 rl = [[i] for i in pl] 

262 rl.append([]) 

263 random.shuffle(rl) 

264 

265 elif tn == '_t_OtherN': 265 ↛ 266line 265 didn't jump to line 266, because the condition on line 265 was never true

266 n = target._for_test_OtherN 

267 rl = list(P(pl, n)) 

268 random.shuffle(rl) 

269 rl = [list(i) for i in rl] 

270 else: 

271 rl = [] 

272 for i in range(3): # HACK: should be enough 

273 rl.extend(list(P(pl, i))) 

274 random.shuffle(rl) 

275 

276 return rl