user.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. import abc
  2. import threading
  3. from conf import Config
  4. from tool.typing import *
  5. from tool.time import HGSTime
  6. from .garbage import GarbageBag, GarbageType
  7. class UserNotSupportError(Exception):
  8. pass
  9. class UserType:
  10. UserTypeStrList: List = ["", "NORMAL", "MANAGER"]
  11. normal: enum = 1
  12. manager: enum = 2
  13. class User(metaclass=abc.ABCMeta):
  14. def __init__(self, name: uname_t, uid: uid_t, user_type: enum, destruct_call: Optional[Callable]):
  15. self._name: uname_t = uname_t(name)
  16. self._uid: uid_t = uid_t(uid)
  17. self._type: enum = enum(user_type)
  18. self._lock = threading.RLock() # 用户 互斥锁
  19. self._destruct_call = destruct_call
  20. def __del__(self):
  21. if self._destruct_call is None:
  22. return
  23. _destruct_call = self._destruct_call
  24. self._destruct_call = None
  25. _destruct_call(self)
  26. def destruct(self):
  27. self.__del__()
  28. def is_manager(self):
  29. try:
  30. self._lock.acquire()
  31. _type = self._type
  32. finally:
  33. self._lock.release()
  34. return _type == UserType.manager
  35. def get_uid(self) -> uid_t:
  36. try:
  37. self._lock.acquire()
  38. uid = self._uid
  39. finally:
  40. self._lock.release()
  41. return uid
  42. def get_name(self) -> uname_t:
  43. try:
  44. self._lock.acquire()
  45. name = self._name
  46. finally:
  47. self._lock.release()
  48. return name
  49. def get_user_type(self) -> enum:
  50. try:
  51. self._lock.acquire()
  52. _type = self._type
  53. finally:
  54. self._lock.release()
  55. return _type
  56. def get_info(self) -> Dict[str, str]:
  57. raise UserNotSupportError
  58. def __repr__(self):
  59. try:
  60. self._lock.acquire()
  61. _type = UserType.UserTypeStrList[self._type]
  62. uid = self._uid
  63. name = self._name
  64. finally:
  65. self._lock.release()
  66. return f"User {uid} {name} is {_type}"
  67. def evaluate(self, is_right: bool) -> score_t:
  68. raise UserNotSupportError
  69. def get_score(self):
  70. raise UserNotSupportError
  71. def get_reputation(self):
  72. raise UserNotSupportError
  73. def get_rubbish(self):
  74. raise UserNotSupportError
  75. def add_score(self, score: score_t) -> score_t:
  76. raise UserNotSupportError
  77. def throw_rubbish(self, garbage: GarbageBag, garbage_type: enum, loc: location_t) -> bool:
  78. raise UserNotSupportError
  79. def check_rubbish(self, garbage: GarbageBag, right: bool, user) -> bool:
  80. raise UserNotSupportError
  81. class NormalUser(User):
  82. def __init__(self, name: uname_t,
  83. uid: uid_t,
  84. reputation: score_t,
  85. rubbish: count_t,
  86. score: score_t,
  87. destruct_call: Optional[Callable]):
  88. super(NormalUser, self).__init__(name, uid, UserType.normal, destruct_call)
  89. self._reputation = score_t(reputation)
  90. self._rubbish = count_t(rubbish)
  91. self._score = score_t(score)
  92. def __repr__(self):
  93. try:
  94. self._lock.acquire()
  95. info = (f"User {self._uid} {self._name} "
  96. f"reputation {self._reputation} "
  97. f"rubbish {self._rubbish} "
  98. f"score {self._score} "
  99. f"is NORMAL")
  100. finally:
  101. self._lock.release()
  102. return info
  103. def get_info(self) -> Dict[str, str]:
  104. """
  105. 获取当前用户的简单信息
  106. :return: 用户信息字典
  107. """
  108. try:
  109. self._lock.acquire()
  110. info = {
  111. "name": str(self._name),
  112. "uid": str(self._uid),
  113. "manager": '0',
  114. "reputation": str(self._reputation),
  115. "rubbish": str(self._rubbish),
  116. "score": str(self._score)
  117. }
  118. finally:
  119. self._lock.release()
  120. return info
  121. def evaluate(self, is_right: bool) -> score_t:
  122. """
  123. 评估信誉积分
  124. 使用朴素贝叶斯公式为基础
  125. 总分值: 1000分
  126. 实际分: P(A|B) * 1000
  127. A=能正确仍对垃圾的概率
  128. B=本次仍对垃圾的概率
  129. 初始概率:
  130. P(A) = 0.3 (default_reputation = 300)
  131. P(B|A) = 0.6
  132. P(B|^A) = 0.3
  133. P(B) = 0.8 * 0.3 + 0.1 * 0.7 = 0.31
  134. p(^B) = 0.69
  135. P(A|B) = P(A) * (P(B|A) / P(B)) = P(A) * 2.5806
  136. P(A|^B) = P(A) * (P(^B|A) / P(^B)) = P(A) * (0.2/0.96) = P(A) * 0.2083
  137. :return: 信誉积分
  138. """
  139. try:
  140. self._lock.acquire()
  141. if is_right and self._rubbish > Config.max_rubbish_week:
  142. return self._reputation # 执行 finally将释放锁
  143. pa = self._reputation / 1000 # P(A)
  144. if pa < 0.01:
  145. pa = 0.01
  146. p_a = 1 - pa # P(^A)
  147. pba, p_ba, pb_a, p_b_a = 0.6, 0.4, 0.3, 0.7 # P(B|A), P(^B|A), P(B|^A), P(^B|^A)
  148. pb = pba * pa + pb_a * p_a # P(B) = P(B|A) * P(A) + P(B|^A) * P(^A)
  149. p_b = p_ba * pa + p_b_a * p_a # P(^B) = P(^B|A) * P(A) + P(^B|^A) * P(^A)
  150. if is_right:
  151. new_pa = pa * (pba / pb) # P(A|B)
  152. else:
  153. new_pa = pa * (p_ba / p_b) # P(A|^B)
  154. new_pa = new_pa * 1000
  155. if int(new_pa) == 0:
  156. new_pa = 1
  157. if int(new_pa) > 1000:
  158. new_pa = 999
  159. amplitude = new_pa - self._reputation # 分差
  160. amplitude_top = 1000 - self._reputation # 距离总分分差
  161. if is_right:
  162. if amplitude >= 20:
  163. amplitude = amplitude * (amplitude_top / 1000) # 涨分抑制
  164. else:
  165. if amplitude <= -20:
  166. amplitude = amplitude * (self._reputation / 1000) # 总分分差月小扣分越高
  167. self._reputation += int(amplitude)
  168. if self._reputation <= 5:
  169. self._reputation = 5
  170. reputation = self._reputation
  171. finally:
  172. self._lock.release()
  173. return reputation
  174. def get_reputation(self):
  175. raise self._reputation
  176. def get_rubbish(self):
  177. raise self._reputation
  178. def get_score(self):
  179. return self._score
  180. def add_score(self, score: score_t) -> score_t:
  181. try:
  182. self._lock.acquire()
  183. tmp = self._score + score
  184. if tmp < 0:
  185. self._score = 0
  186. return 0
  187. elif tmp > Config.max_score:
  188. self._score = Config.max_score
  189. return Config.max_score
  190. self._score += score
  191. score = self._score
  192. finally:
  193. self._lock.release()
  194. return score
  195. def throw_rubbish(self, garbage: GarbageBag, garbage_type: enum, loc: location_t = Config.base_location) -> bool:
  196. """
  197. 垃圾投放
  198. :param garbage: 垃圾袋
  199. :param garbage_type: 垃圾类别
  200. :param loc: 地区
  201. :return:
  202. """
  203. try:
  204. self._lock.acquire()
  205. if self._rubbish > Config.max_rubbish_week: # 大于上限, 扣分
  206. self.add_score(-3)
  207. elif self._rubbish > Config.limit_rubbish_week: # 大于最大上限, 不再允许扔垃圾
  208. return False
  209. if garbage.is_use() or garbage.is_check()[0]: # 垃圾袋被使用
  210. return False
  211. garbage.config_use(garbage_type, HGSTime(), self._uid, loc)
  212. self._rubbish += 1
  213. finally:
  214. self._lock.release()
  215. return True
  216. def check_rubbish(self, garbage: GarbageBag, right: bool, user: User) -> bool:
  217. raise UserNotSupportError
  218. class ManagerUser(User):
  219. def __init__(self, name: uname_t,
  220. uid: uid_t,
  221. destruct_call: Optional[Callable]):
  222. super(ManagerUser, self).__init__(name, uid, UserType.manager, destruct_call)
  223. def check_rubbish(self, garbage: GarbageBag, result: bool, user: User) -> bool:
  224. """
  225. 检查垃圾
  226. :param garbage: 垃圾袋
  227. :param result: 结果
  228. :param user: 垃圾袋投放者
  229. :return:
  230. """
  231. if (not garbage.is_use()) or garbage.is_check()[0] or user.get_uid() != garbage.get_user(): # 调用时已经有锁
  232. return False
  233. try:
  234. self._lock.acquire()
  235. garbage.config_check(result, self._uid)
  236. user.evaluate(result)
  237. if result:
  238. if garbage.get_type() == GarbageType.recyclable:
  239. user.add_score(3)
  240. elif garbage.get_type() == GarbageType.kitchen or garbage.get_type() == GarbageType.hazardous:
  241. user.add_score(2)
  242. else:
  243. user.add_score(1)
  244. else:
  245. user.add_score(-4)
  246. finally:
  247. self._lock.release()
  248. return True
  249. def get_info(self) -> Dict[str, str]:
  250. try:
  251. self._lock.acquire()
  252. info = {
  253. "name": str(self._name),
  254. "uid": str(self._uid),
  255. "manager": '1'
  256. }
  257. finally:
  258. self._lock.release()
  259. return info
  260. def get_reputation(self):
  261. raise 0
  262. def get_rubbish(self):
  263. raise 0
  264. def get_score(self):
  265. return 0