All checks were successful
ci/woodpecker/push/check_format Pipeline was successful
202 lines
6.9 KiB
Python
202 lines
6.9 KiB
Python
"""
|
|
Copyright (c) 2024 zhbaor <zhbaor@zhaozuohong.vip>
|
|
|
|
This file is part of mower-ng (https://git.zhaozuohong.vip/mower-ng/mower-ng).
|
|
|
|
Mower-ng is free software: you may copy, redistribute and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation, version 3 or later.
|
|
|
|
This file is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
This file incorporates work covered by the following copyright and
|
|
permission notice:
|
|
|
|
Copyright (c) 2023 Shawnsdaddy <wu2xx@dukes.jmu.edu>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
"""
|
|
|
|
import copy
|
|
from enum import Enum
|
|
from typing import Optional, Self
|
|
|
|
from mower.utils.log import logger
|
|
from mower.utils.logic_expression import LogicExpression
|
|
|
|
|
|
class PlanTriggerTiming(Enum):
|
|
"副表触发时机"
|
|
|
|
BEGINNING = 0
|
|
"任务开始"
|
|
BEFORE_PLANNING = 300
|
|
"下班结束"
|
|
AFTER_PLANNING = 600
|
|
"上班结束"
|
|
END = 999
|
|
"任务结束"
|
|
|
|
|
|
def to_list(str_data: str) -> list[str]:
|
|
lst = str_data.replace(",", ",").split(",")
|
|
return [x.strip() for x in lst]
|
|
|
|
|
|
class PlanConfig:
|
|
def __init__(
|
|
self,
|
|
rest_in_full: str,
|
|
exhaust_require: str,
|
|
resting_priority: str,
|
|
ling_xi: int = 0,
|
|
workaholic: str = "",
|
|
max_resting_count: int = 4,
|
|
free_blacklist: str = "",
|
|
resting_threshold: float = 0.5,
|
|
refresh_trading_config: str = "",
|
|
free_room: bool = False,
|
|
):
|
|
"""排班的设置
|
|
|
|
Args:
|
|
rest_in_full: 回满
|
|
exhaust_require: 耗尽
|
|
resting_priority: 低优先级
|
|
ling_xi: 令夕模式
|
|
workaholic: 0心情工作
|
|
max_resting_count: 最大组人数
|
|
free_blacklist: 宿舍黑名单
|
|
resting_threshold: 心情阈值
|
|
refresh_trading_config: 跑单时间刷新干员
|
|
free_room: 宿舍不养闲人模式
|
|
"""
|
|
self.rest_in_full = to_list(rest_in_full)
|
|
self.exhaust_require = to_list(exhaust_require)
|
|
self.workaholic = to_list(workaholic)
|
|
self.resting_priority = to_list(resting_priority)
|
|
self.max_resting_count = max_resting_count
|
|
self.free_blacklist = to_list(free_blacklist)
|
|
# 0 为均衡模式
|
|
# 1 为感知信息模式
|
|
# 2 为人间烟火模式
|
|
self.ling_xi = ling_xi
|
|
self.resting_threshold = resting_threshold
|
|
self.free_room = free_room
|
|
# 格式为 干员名字+ 括弧 +指定房间(逗号分隔)
|
|
# 不指定房间则默认全跑单站
|
|
# example: 阿米娅,夕,令
|
|
# 夕(room_3_1,room_1_3),令(room_3_1)
|
|
self.refresh_trading_config = to_list(refresh_trading_config)
|
|
|
|
def is_rest_in_full(self, agent_name) -> bool:
|
|
return agent_name in self.rest_in_full
|
|
|
|
def is_exhaust_require(self, agent_name) -> bool:
|
|
return agent_name in self.exhaust_require
|
|
|
|
def is_workaholic(self, agent_name) -> bool:
|
|
return agent_name in self.workaholic
|
|
|
|
def is_resting_priority(self, agent_name) -> bool:
|
|
return agent_name in self.resting_priority
|
|
|
|
def is_free_blacklist(self, agent_name) -> bool:
|
|
return agent_name in self.free_blacklist
|
|
|
|
def is_refresh_trading(self, agent_name) -> list[bool, list[str]]:
|
|
match = next(
|
|
(e for e in self.refresh_trading_config if agent_name in e.lower()),
|
|
None,
|
|
)
|
|
if match is not None:
|
|
if match.replace(agent_name, "") != "":
|
|
return [True, match.replace(agent_name, "").split(",")]
|
|
else:
|
|
return [True, []]
|
|
else:
|
|
return [False, []]
|
|
|
|
def merge_config(self, target: Self) -> Self:
|
|
n = copy.deepcopy(self)
|
|
for p in [
|
|
"rest_in_full",
|
|
"exhaust_require",
|
|
"workaholic",
|
|
"resting_priority",
|
|
"free_blacklist",
|
|
"refresh_trading_config",
|
|
]:
|
|
p_dict = set(getattr(n, p))
|
|
target_p = set(getattr(target, p))
|
|
setattr(n, p, list(p_dict.union(target_p)))
|
|
return n
|
|
|
|
|
|
class Room:
|
|
def __init__(self, agent: str, group: str, replacement: list[str]):
|
|
"""房间
|
|
|
|
Args:
|
|
agent: 主力干员
|
|
group: 组
|
|
replacement: 替换组
|
|
"""
|
|
self.agent = agent
|
|
self.group = group
|
|
self.replacement = replacement
|
|
|
|
|
|
class Plan:
|
|
def __init__(
|
|
self,
|
|
plan: dict[str, Room],
|
|
config: PlanConfig,
|
|
trigger: Optional[LogicExpression] = None,
|
|
task: Optional[dict[str, list[str]]] = None,
|
|
trigger_timing: Optional[str] = None,
|
|
):
|
|
"""
|
|
Args:
|
|
plan: 基建计划 or 触发备用plan 的排班表,只需要填和默认不一样的部分
|
|
config: 基建计划相关配置,必须填写全部配置
|
|
trigger: 触发备用plan 的条件(必填)就是每次最多只有一个备用plan触发
|
|
task: 触发备用plan 的时间生成的任务(选填)
|
|
trigger_timing: 触发时机
|
|
"""
|
|
self.plan = plan
|
|
self.config = config
|
|
self.trigger = trigger
|
|
self.task = task
|
|
self.trigger_timing = self.set_timing_enum(trigger_timing)
|
|
|
|
@staticmethod
|
|
def set_timing_enum(value: str) -> PlanTriggerTiming:
|
|
"将字符串转换为副表触发时机"
|
|
try:
|
|
return PlanTriggerTiming[value.upper()]
|
|
except Exception as e:
|
|
logger.exception(e)
|
|
return PlanTriggerTiming.AFTER_PLANNING
|