user.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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):
  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. def is_manager(self):
  20. try:
  21. self._lock.acquire()
  22. _type = self._type
  23. finally:
  24. self._lock.release()
  25. return _type == UserType.manager
  26. def get_uid(self) -> uid_t:
  27. try:
  28. self._lock.acquire()
  29. uid = self._uid
  30. finally:
  31. self._lock.release()
  32. return uid
  33. def get_name(self) -> uname_t:
  34. try:
  35. self._lock.acquire()
  36. name = self._name
  37. finally:
  38. self._lock.release()
  39. return name
  40. def get_user_type(self) -> enum:
  41. try:
  42. self._lock.acquire()
  43. _type = self._type
  44. finally:
  45. self._lock.release()
  46. return _type
  47. def get_info(self) -> Dict[str, str]:
  48. raise UserNotSupportError
  49. def __repr__(self):
  50. try:
  51. self._lock.acquire()
  52. _type = UserType.UserTypeStrList[self._type]
  53. uid = self._uid
  54. name = self._name
  55. finally:
  56. self._lock.release()
  57. return f"User {uid} {name} is {_type}"
  58. def evaluate(self, is_right: bool) -> score_t:
  59. raise UserNotSupportError
  60. def get_score(self):
  61. raise UserNotSupportError
  62. def add_score(self, score: score_t) -> score_t:
  63. raise UserNotSupportError
  64. def throw_rubbish(self, garbage: GarbageBag, garbage_type: enum, loc: location_t) -> bool:
  65. raise UserNotSupportError
  66. def check_rubbish(self, garbage: GarbageBag, right: bool, user) -> bool:
  67. raise UserNotSupportError
  68. class NormalUser(User):
  69. def __init__(self, name: uname_t, uid: uid_t, reputation: score_t, rubbish: count_t, score: score_t):
  70. super(NormalUser, self).__init__(name, uid, UserType.normal)
  71. self._reputation = score_t(reputation)
  72. self._rubbish = count_t(rubbish)
  73. self._score = score_t(score)
  74. def __repr__(self):
  75. try:
  76. self._lock.acquire()
  77. info = (f"User {self._uid} {self._name} "
  78. f"reputation {self._reputation} "
  79. f"rubbish {self._rubbish} "
  80. f"score {self._score} "
  81. f"is NORMAL")
  82. finally:
  83. self._lock.release()
  84. return info
  85. def get_info(self) -> Dict[str, str]:
  86. """
  87. 获取当前用户的简单信息
  88. :return: 用户信息字典
  89. """
  90. try:
  91. self._lock.acquire()
  92. info = {
  93. "name": str(self._name),
  94. "uid": str(self._uid),
  95. "manager": '0',
  96. "reputation": str(self._reputation),
  97. "rubbish": str(self._rubbish),
  98. "score": str(self._score)
  99. }
  100. finally:
  101. self._lock.release()
  102. return info
  103. def evaluate(self, is_right: bool) -> score_t:
  104. """
  105. 评估信誉积分
  106. 使用朴素贝叶斯公式为基础
  107. 总分值: 1000分
  108. 实际分: P(A|B) * 1000
  109. A=能正确仍对垃圾的概率
  110. B=本次仍对垃圾的概率
  111. 初始概率:
  112. P(A) = 0.3 (default_reputation = 300)
  113. P(B|A) = 0.6
  114. P(B|^A) = 0.3
  115. P(B) = 0.8 * 0.3 + 0.1 * 0.7 = 0.31
  116. p(^B) = 0.69
  117. P(A|B) = P(A) * (P(B|A) / P(B)) = P(A) * 2.5806
  118. P(A|^B) = P(A) * (P(^B|A) / P(^B)) = P(A) * (0.2/0.96) = P(A) * 0.2083
  119. :return: 信誉积分
  120. """
  121. try:
  122. self._lock.acquire()
  123. if is_right and self._rubbish > Config.max_rubbish_week:
  124. return self._reputation # 执行 finally将释放锁
  125. pa = self._reputation / 1000 # P(A)
  126. if pa < 0.01:
  127. pa = 0.01
  128. p_a = 1 - pa # P(^A)
  129. 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)
  130. pb = pba * pa + pb_a * p_a # P(B) = P(B|A) * P(A) + P(B|^A) * P(^A)
  131. p_b = p_ba * pa + p_b_a * p_a # P(^B) = P(^B|A) * P(A) + P(^B|^A) * P(^A)
  132. if is_right:
  133. new_pa = pa * (pba / pb) # P(A|B)
  134. else:
  135. new_pa = pa * (p_ba / p_b) # P(A|^B)
  136. new_pa = new_pa * 1000
  137. if int(new_pa) == 0:
  138. new_pa = 1
  139. if int(new_pa) > 1000:
  140. new_pa = 999
  141. amplitude = new_pa - self._reputation # 分差
  142. amplitude_top = 1000 - self._reputation # 距离总分分差
  143. if is_right:
  144. if amplitude >= 20:
  145. amplitude = amplitude * (amplitude_top / 1000) # 涨分抑制
  146. else:
  147. if amplitude <= -20:
  148. amplitude = amplitude * (self._reputation / 1000) # 总分分差月小扣分越高
  149. self._reputation += int(amplitude)
  150. if self._reputation <= 5:
  151. self._reputation = 5
  152. reputation = self._reputation
  153. finally:
  154. self._lock.release()
  155. return reputation
  156. def get_score(self):
  157. return self._score
  158. def add_score(self, score: score_t) -> score_t:
  159. try:
  160. self._lock.acquire()
  161. tmp = self._score + score
  162. if tmp < 0:
  163. self._score = 0
  164. return 0
  165. elif tmp > Config.max_score:
  166. self._score = Config.max_score
  167. return Config.max_score
  168. self._score += score
  169. score = self._score
  170. finally:
  171. self._lock.release()
  172. return score
  173. def throw_rubbish(self, garbage: GarbageBag, garbage_type: enum, loc: location_t = Config.base_location) -> bool:
  174. try:
  175. self._lock.acquire()
  176. if self._rubbish > Config.max_rubbish_week:
  177. self.add_score(-3)
  178. elif self._rubbish > Config.limit_rubbish_week:
  179. return False
  180. if garbage.is_use() or garbage.is_check()[0]:
  181. return False
  182. garbage.config_use(garbage_type, HGSTime(), self._uid, loc)
  183. self._rubbish += 1
  184. finally:
  185. self._lock.release()
  186. return True
  187. def check_rubbish(self, garbage: GarbageBag, right: bool, user: User) -> bool:
  188. raise UserNotSupportError
  189. class ManagerUser(User):
  190. def __init__(self, name: uname_t, uid: uid_t):
  191. super(ManagerUser, self).__init__(name, uid, UserType.manager)
  192. def check_rubbish(self, garbage: GarbageBag, right: bool, user: User) -> bool:
  193. if (not garbage.is_use()) or garbage.is_check()[0] or user.get_uid() != garbage.get_user(): # 调用时已经有锁
  194. return False
  195. try:
  196. self._lock.acquire()
  197. garbage.config_check(right, self._uid)
  198. user.evaluate(right)
  199. if right:
  200. if garbage.get_type() == GarbageType.recyclable:
  201. user.add_score(3)
  202. elif garbage.get_type() == GarbageType.kitchen or garbage.get_type() == GarbageType.hazardous:
  203. user.add_score(2)
  204. else:
  205. user.add_score(1)
  206. else:
  207. user.add_score(-4)
  208. finally:
  209. self._lock.release()
  210. return True
  211. def get_info(self) -> Dict[str, str]:
  212. try:
  213. self._lock.acquire()
  214. info = {
  215. "name": str(self._name),
  216. "uid": str(self._uid),
  217. "manager": '1'
  218. }
  219. finally:
  220. self._lock.release()
  221. return info