/// <summary> /// 计算指定地区的综合工作指数 /// /// 综合工作指数 = SUM(缩放平移过的建筑工作效率 * 建筑优先级) /// 厢房效率不计入统计 /// /// 由于必须在最开始执行,所以无法使用 prepared data /// </summary> /// <param name="partId"></param> /// <param name="placeId"></param> /// <returns></returns> private static float GetCompositeWorkIndex(int partId, int placeId) { float compositeWorkIndex = 0.0f; // 统计所有建筑的工作效率(厢房效率不计入统计) var buildings = DateFile.instance.homeBuildingsDate[partId][placeId]; foreach (int buildingIndex in buildings.Keys) { if (!Original.BuildingNeedsWorker(partId, placeId, buildingIndex)) { continue; } if (Bedroom.IsBedroom(partId, placeId, buildingIndex)) { continue; } if (DateFile.instance.actorsWorkingDate.ContainsKey(partId) && DateFile.instance.actorsWorkingDate[partId].ContainsKey(placeId) && DateFile.instance.actorsWorkingDate[partId][placeId].ContainsKey(buildingIndex)) { int workerId = DateFile.instance.actorsWorkingDate[partId][placeId][buildingIndex]; int workEffectiveness = Original.GetWorkEffectiveness(partId, placeId, buildingIndex, workerId); float scaledWorkEffectiveness = (workEffectiveness - 100f) / 100f; int priority = HumanResource.GetBuildingWorkingPriority(partId, placeId, buildingIndex); compositeWorkIndex += scaledWorkEffectiveness * priority; } } return(compositeWorkIndex); }
// 对于每个需要厢房才能满效率的建筑,尝试找到邻接厢房,生成建筑列表和候选厢房列表 private static void GetBedroomsForWork_PrepareData(int partId, int placeId, Dictionary <int, BuildingWorkInfo> buildings, Dictionary <int, List <int> > attrCandidates, Dictionary <int, Dictionary <int, int> > workerAttrs, Dictionary <int, BuildingInfo> buildingsNeedBedroom, Dictionary <int, BedroomInfo> bedroomCandidates) { // 遍历所有建筑 foreach (var info in buildings.Values) { // 排除厢房 if (info.requiredAttrId == 0) { continue; } // 如果没有候选人,则不寻找邻接厢房 var sortedWorkerIds = attrCandidates[info.requiredAttrId]; if (sortedWorkerIds.Any()) { int workerId = sortedWorkerIds[0]; int attrMaxValue = workerAttrs[workerId][info.requiredAttrId]; // 凭单个候选人无法满效率 if (attrMaxValue < info.fullWorkingAttrValue) { // 找到邻接厢房,并创建供之后使用的数据结构 var adjacentBedrooms = Bedroom.GetAdjacentBedrooms(partId, placeId, info.buildingIndex); // 记录需要厢房的建筑信息 buildingsNeedBedroom[info.buildingIndex] = new BuildingInfo { buildingWorkInfo = info, adjacentBedrooms = adjacentBedrooms, }; // 记录候选厢房的信息 foreach (int bedroomBuildingIndex in adjacentBedrooms) { if (!bedroomCandidates.ContainsKey(bedroomBuildingIndex)) { bedroomCandidates[bedroomBuildingIndex] = new BedroomInfo { buildingIndex = bedroomBuildingIndex, buildingsNeedBedroom = new List <int>(), }; } bedroomCandidates[bedroomBuildingIndex].buildingsNeedBedroom.Add(info.buildingIndex); } } } } }
// 获取增加工作效率的厢房列表 // 如果某个建筑找不到标准状态下满效率的工作人选,那么就看其邻接区域有没有厢房,有则选择一个当作增加工作效率的厢房。 public static Dictionary <int, List <BuildingWorkInfo> > GetBedroomsForWork(int partId, int placeId, Dictionary <int, BuildingWorkInfo> buildings, Dictionary <int, List <int> > attrCandidates, Dictionary <int, Dictionary <int, int> > workerAttrs) { // 对于每个需要厢房才能满效率的建筑,尝试找到邻接厢房,生成需要厢房辅助的建筑列表和候选厢房列表 // buildingIndex -> BuildingInfo var buildingsNeedBedroom = new Dictionary <int, BuildingInfo>(); // bedroomIndex -> BedroomInfo var bedroomCandidates = new Dictionary <int, BedroomInfo>(); Bedroom.GetBedroomsForWork_PrepareData(partId, placeId, buildings, attrCandidates, workerAttrs, buildingsNeedBedroom, bedroomCandidates); // 按建筑优先级对需要厢房辅助的建筑排序,然后对于每个建筑,在其候选厢房中选择优先级最高的厢房 List <int> sortedBuildingsNeedBedroom = buildingsNeedBedroom .OrderByDescending(entry => entry.Value.buildingWorkInfo.priority) .Select(entry => entry.Key).ToList(); // 厢房 ID -> 该厢房辅助的建筑信息列表 // bedroomIndex -> [BuildingWorkInfo, ] var bedroomsForWork = new Dictionary <int, List <BuildingWorkInfo> >(); foreach (int buildingIndex in sortedBuildingsNeedBedroom) { int bedroomIndex = SelectBedroomForWork(partId, placeId, buildingIndex, buildings, buildingsNeedBedroom, bedroomCandidates); if (bedroomIndex < 0) { continue; } if (!bedroomsForWork.ContainsKey(bedroomIndex)) { bedroomsForWork[bedroomIndex] = new List <BuildingWorkInfo>(); } bedroomsForWork[bedroomIndex].Add(buildings[buildingIndex]); } return(bedroomsForWork); }
public static List <int> GetAdjacentBedrooms(int partId, int placeId, int buildingIndex) { var adjacentBedrooms = new List <int>(); int[] adjacentBuildingIndexes = HomeSystem.instance.GetBuildingNeighbor(partId, placeId, buildingIndex); foreach (int adjacentBuildingIndex in adjacentBuildingIndexes) { if (!DateFile.instance.homeBuildingsDate[partId][placeId].ContainsKey(adjacentBuildingIndex)) { continue; } if (!Bedroom.IsBedroom(partId, placeId, adjacentBuildingIndex)) { continue; } adjacentBedrooms.Add(adjacentBuildingIndex); } return(adjacentBedrooms); }
/// <summary> /// 计算指定地区的工作统计信息 /// /// 综合工作指数 = SUM(缩放平移过的建筑工作效率 * 建筑优先级) /// 厢房效率不计入统计 /// /// 由于必须在最开始执行,所以无法使用 prepared data /// </summary> /// <param name="partId"></param> /// <param name="placeId"></param> /// <returns></returns> private static WorkingStats GetWorkingStats(int partId, int placeId) { var stats = new WorkingStats(); // 统计所有建筑的工作效率(厢房效率不计入统计) var buildings = DateFile.instance.homeBuildingsDate[partId][placeId]; foreach (int buildingIndex in buildings.Keys) { if (!Original.BuildingNeedsWorker(partId, placeId, buildingIndex)) { continue; } if (Bedroom.IsBedroom(partId, placeId, buildingIndex)) { continue; } if (DateFile.instance.actorsWorkingDate.ContainsKey(partId) && DateFile.instance.actorsWorkingDate[partId].ContainsKey(placeId) && DateFile.instance.actorsWorkingDate[partId][placeId].ContainsKey(buildingIndex)) { int workerId = DateFile.instance.actorsWorkingDate[partId][placeId][buildingIndex]; int workEffectiveness = Original.GetWorkEffectiveness(partId, placeId, buildingIndex, workerId); float scaledWorkEffectiveness = (workEffectiveness - 100f) / 100f; float priority = HumanResource.GetBuildingWorkingPriority(partId, placeId, buildingIndex, withAdjacentBedrooms: false); ++stats.nProductiveBuildings; stats.avgWorkEffectiveness += workEffectiveness / 200f; stats.compositeWorkIndex += scaledWorkEffectiveness * priority; } } if (stats.nProductiveBuildings > 0) { stats.avgWorkEffectiveness /= stats.nProductiveBuildings; } return(stats); }
/// <summary> /// 获取邻接厢房对指定建筑的能力加成 /// </summary> /// <param name="partId"></param> /// <param name="placeId"></param> /// <param name="buildingIndex"></param> /// <param name="requiredAttrId"></param> /// <returns></returns> private static int GetAdjacentAttrBonus(int partId, int placeId, int buildingIndex, int requiredAttrId) { int totalAdjacentAttrValue = 0; foreach (int adjacentBuildingIndex in Bedroom.GetAdjacentBedrooms(partId, placeId, buildingIndex)) { if (!DateFile.instance.actorsWorkingDate.ContainsKey(partId) || !DateFile.instance.actorsWorkingDate[partId].ContainsKey(placeId) || !DateFile.instance.actorsWorkingDate[partId][placeId].ContainsKey(adjacentBuildingIndex)) { continue; } int adjacentActorId = DateFile.instance.actorsWorkingDate[partId][placeId][adjacentBuildingIndex]; int adjacentAttrValue = (requiredAttrId > 0) ? int.Parse(DateFile.instance.GetActorDate(adjacentActorId, requiredAttrId)) : 0; adjacentAttrValue = Original.ToStandardAttrValue(requiredAttrId, adjacentAttrValue); totalAdjacentAttrValue += adjacentAttrValue; } return(totalAdjacentAttrValue); }
/// <summary> /// 为所有厢房安排工作人员 /// </summary> private void AssignBedroomWorkers() { // 厢房 ID -> 该厢房辅助的建筑信息列表 // bedroomIndex -> [BuildingWorkInfo, ] var bedroomsForWork = Bedroom.GetBedroomsForWork(this.partId, this.placeId, this.buildings, this.attrCandidates, this.workerAttrs); // 更新辅助类厢房的优先级 // 辅助类厢房优先级 = 基础优先级 + SUM(辅助建筑优先级) // bedroomIndex -> priority var auxiliaryBedroomsPriorities = new Dictionary <int, int>(); foreach (var entry in bedroomsForWork) { int bedroomIndex = entry.Key; var relatedBuildings = entry.Value; int basePriority = 7; int priority = basePriority * WORKING_PRIORITY_STEP_SIZE + relatedBuildings.Select(info => info.priority).Sum(); auxiliaryBedroomsPriorities[bedroomIndex] = priority; } // 对于辅助类厢房,按优先级依次分配合适的人选 MajordomoWindow.instance.AppendMessage(this.currDate, Message.IMPORTANCE_LOWEST, TaiwuCommon.SetColor(TaiwuCommon.COLOR_DARK_GRAY, "开始指派辅助类厢房……")); var sortedAuxiliaryBedrooms = auxiliaryBedroomsPriorities.OrderByDescending(entry => entry.Value).Select(entry => entry.Key); foreach (int bedroomIndex in sortedAuxiliaryBedrooms) { int selectedWorkerId = this.SelectAuxiliaryBedroomWorker(bedroomIndex, bedroomsForWork[bedroomIndex]); if (selectedWorkerId >= 0) { Original.SetBuildingWorker(this.partId, this.placeId, bedroomIndex, selectedWorkerId); } Output.LogAuxiliaryBedroomAndWorker(bedroomIndex, bedroomsForWork[bedroomIndex], auxiliaryBedroomsPriorities[bedroomIndex], selectedWorkerId, this.partId, this.placeId, this.currDate, this.workerAttrs); } // 对于一般厢房,按优先级依次分配合适的人选 MajordomoWindow.instance.AppendMessage(this.currDate, Message.IMPORTANCE_LOWEST, TaiwuCommon.SetColor(TaiwuCommon.COLOR_DARK_GRAY, "开始指派一般厢房……")); var sortedBedrooms = this.buildings.Where(entry => entry.Value.IsBedroom()) .OrderByDescending(entry => entry.Value.priority).Select(entry => entry.Value); foreach (var info in sortedBedrooms) { if (this.excludedBuildings.Contains(info.buildingIndex)) { continue; } int selectedWorkerId = this.SelectBuildingWorker(info.buildingIndex, info.requiredAttrId); if (selectedWorkerId >= 0) { Original.SetBuildingWorker(this.partId, this.placeId, info.buildingIndex, selectedWorkerId); } Output.LogBuildingAndWorker(info, selectedWorkerId, this.partId, this.placeId, this.currDate, this.workerAttrs); } }