123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- import abc
- import threading
- from conf import Config
- from tool.typing import *
- from tool.time import HGSTime
- from .garbage import GarbageBag, GarbageType
- class UserNotSupportError(Exception):
- pass
- class UserType:
- UserTypeStrList: List = ["", "NORMAL", "MANAGER"]
- normal: enum = 1
- manager: enum = 2
- class User(metaclass=abc.ABCMeta):
- def __init__(self, name: uname_t, uid: uid_t, user_type: enum, destruct_call: Optional[Callable]):
- self._name: uname_t = uname_t(name)
- self._uid: uid_t = uid_t(uid)
- self._type: enum = enum(user_type)
- self._lock = threading.RLock() # 用户 互斥锁
- self._destruct_call = destruct_call
- def __del__(self):
- if self._destruct_call is None:
- return
- _destruct_call = self._destruct_call
- self._destruct_call = None
- _destruct_call(self)
- def destruct(self):
- self.__del__()
- def is_manager(self):
- try:
- self._lock.acquire()
- _type = self._type
- finally:
- self._lock.release()
- return _type == UserType.manager
- def get_uid(self) -> uid_t:
- try:
- self._lock.acquire()
- uid = self._uid
- finally:
- self._lock.release()
- return uid
- def get_name(self) -> uname_t:
- try:
- self._lock.acquire()
- name = self._name
- finally:
- self._lock.release()
- return name
- def get_user_type(self) -> enum:
- try:
- self._lock.acquire()
- _type = self._type
- finally:
- self._lock.release()
- return _type
- def get_info(self) -> Dict[str, str]:
- raise UserNotSupportError
- def __repr__(self):
- try:
- self._lock.acquire()
- _type = UserType.UserTypeStrList[self._type]
- uid = self._uid
- name = self._name
- finally:
- self._lock.release()
- return f"User {uid} {name} is {_type}"
- def evaluate(self, is_right: bool) -> score_t:
- raise UserNotSupportError
- def get_score(self):
- raise UserNotSupportError
- def get_reputation(self):
- raise UserNotSupportError
- def get_rubbish(self):
- raise UserNotSupportError
- def add_score(self, score: score_t) -> score_t:
- raise UserNotSupportError
- def throw_rubbish(self, garbage: GarbageBag, garbage_type: enum, loc: location_t) -> bool:
- raise UserNotSupportError
- def check_rubbish(self, garbage: GarbageBag, right: bool, user) -> bool:
- raise UserNotSupportError
- class NormalUser(User):
- def __init__(self, name: uname_t,
- uid: uid_t,
- reputation: score_t,
- rubbish: count_t,
- score: score_t,
- destruct_call: Optional[Callable]):
- super(NormalUser, self).__init__(name, uid, UserType.normal, destruct_call)
- self._reputation = score_t(reputation)
- self._rubbish = count_t(rubbish)
- self._score = score_t(score)
- def __repr__(self):
- try:
- self._lock.acquire()
- info = (f"User {self._uid} {self._name} "
- f"reputation {self._reputation} "
- f"rubbish {self._rubbish} "
- f"score {self._score} "
- f"is NORMAL")
- finally:
- self._lock.release()
- return info
- def get_info(self) -> Dict[str, str]:
- """
- 获取当前用户的简单信息
- :return: 用户信息字典
- """
- try:
- self._lock.acquire()
- info = {
- "name": str(self._name),
- "uid": str(self._uid),
- "manager": '0',
- "reputation": str(self._reputation),
- "rubbish": str(self._rubbish),
- "score": str(self._score)
- }
- finally:
- self._lock.release()
- return info
- def evaluate(self, is_right: bool) -> score_t:
- """
- 评估信誉积分
- 使用朴素贝叶斯公式为基础
- 总分值: 1000分
- 实际分: P(A|B) * 1000
- A=能正确仍对垃圾的概率
- B=本次仍对垃圾的概率
- 初始概率:
- P(A) = 0.3 (default_reputation = 300)
- P(B|A) = 0.6
- P(B|^A) = 0.3
- P(B) = 0.8 * 0.3 + 0.1 * 0.7 = 0.31
- p(^B) = 0.69
- P(A|B) = P(A) * (P(B|A) / P(B)) = P(A) * 2.5806
- P(A|^B) = P(A) * (P(^B|A) / P(^B)) = P(A) * (0.2/0.96) = P(A) * 0.2083
- :return: 信誉积分
- """
- try:
- self._lock.acquire()
- if is_right and self._rubbish > Config.max_rubbish_week:
- return self._reputation # 执行 finally将释放锁
- pa = self._reputation / 1000 # P(A)
- if pa < 0.01:
- pa = 0.01
- p_a = 1 - pa # P(^A)
- 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)
- pb = pba * pa + pb_a * p_a # P(B) = P(B|A) * P(A) + P(B|^A) * P(^A)
- p_b = p_ba * pa + p_b_a * p_a # P(^B) = P(^B|A) * P(A) + P(^B|^A) * P(^A)
- if is_right:
- new_pa = pa * (pba / pb) # P(A|B)
- else:
- new_pa = pa * (p_ba / p_b) # P(A|^B)
- new_pa = new_pa * 1000
- if int(new_pa) == 0:
- new_pa = 1
- if int(new_pa) > 1000:
- new_pa = 999
- amplitude = new_pa - self._reputation # 分差
- amplitude_top = 1000 - self._reputation # 距离总分分差
- if is_right:
- if amplitude >= 20:
- amplitude = amplitude * (amplitude_top / 1000) # 涨分抑制
- else:
- if amplitude <= -20:
- amplitude = amplitude * (self._reputation / 1000) # 总分分差月小扣分越高
- self._reputation += int(amplitude)
- if self._reputation <= 5:
- self._reputation = 5
- reputation = self._reputation
- finally:
- self._lock.release()
- return reputation
- def get_reputation(self):
- raise self._reputation
- def get_rubbish(self):
- raise self._reputation
- def get_score(self):
- return self._score
- def add_score(self, score: score_t) -> score_t:
- try:
- self._lock.acquire()
- tmp = self._score + score
- if tmp < 0:
- self._score = 0
- return 0
- elif tmp > Config.max_score:
- self._score = Config.max_score
- return Config.max_score
- self._score += score
- score = self._score
- finally:
- self._lock.release()
- return score
- def throw_rubbish(self, garbage: GarbageBag, garbage_type: enum, loc: location_t = Config.base_location) -> bool:
- """
- 垃圾投放
- :param garbage: 垃圾袋
- :param garbage_type: 垃圾类别
- :param loc: 地区
- :return:
- """
- try:
- self._lock.acquire()
- if self._rubbish > Config.max_rubbish_week: # 大于上限, 扣分
- self.add_score(-3)
- elif self._rubbish > Config.limit_rubbish_week: # 大于最大上限, 不再允许扔垃圾
- return False
- if garbage.is_use() or garbage.is_check()[0]: # 垃圾袋被使用
- return False
- garbage.config_use(garbage_type, HGSTime(), self._uid, loc)
- self._rubbish += 1
- finally:
- self._lock.release()
- return True
- def check_rubbish(self, garbage: GarbageBag, right: bool, user: User) -> bool:
- raise UserNotSupportError
- class ManagerUser(User):
- def __init__(self, name: uname_t,
- uid: uid_t,
- destruct_call: Optional[Callable]):
- super(ManagerUser, self).__init__(name, uid, UserType.manager, destruct_call)
- def check_rubbish(self, garbage: GarbageBag, result: bool, user: User) -> bool:
- """
- 检查垃圾
- :param garbage: 垃圾袋
- :param result: 结果
- :param user: 垃圾袋投放者
- :return:
- """
- if (not garbage.is_use()) or garbage.is_check()[0] or user.get_uid() != garbage.get_user(): # 调用时已经有锁
- return False
- try:
- self._lock.acquire()
- garbage.config_check(result, self._uid)
- user.evaluate(result)
- if result:
- if garbage.get_type() == GarbageType.recyclable:
- user.add_score(3)
- elif garbage.get_type() == GarbageType.kitchen or garbage.get_type() == GarbageType.hazardous:
- user.add_score(2)
- else:
- user.add_score(1)
- else:
- user.add_score(-4)
- finally:
- self._lock.release()
- return True
- def get_info(self) -> Dict[str, str]:
- try:
- self._lock.acquire()
- info = {
- "name": str(self._name),
- "uid": str(self._uid),
- "manager": '1'
- }
- finally:
- self._lock.release()
- return info
- def get_reputation(self):
- raise 0
- def get_rubbish(self):
- raise 0
- def get_score(self):
- return 0
|