using Newtonsoft.Json; using PlcSiemens.Core.Extension; using ServiceCenter.Extensions; using ServiceCenter.Logs; using ServiceCenter.SqlSugars; using SqlSugar; using System.ComponentModel; using WCS.Core; using WCS.Entity; using WCS.Entity.Protocol.Protocol.Robot; using WCS.Entity.Protocol.Robot; using WCS.Entity.Protocol.Station; using WCS.WorkEngineering.Extensions; using WCS.WorkEngineering.Model.WMS; using WCS.WorkEngineering.Worlds.环形库.环形库; using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags; using TaskStatus = WCS.Entity.TaskStatus; namespace WCS.WorkEngineering.Systems { /// /// 机械臂 /// [BelongTo(typeof(RingWorld1))] [Description("机械臂")] public class 机械臂 : DeviceSystem> { protected override bool ParallelDo => true; /// /// 取货点设备集合 /// private Dictionary> PickUpDevices = new(); /// /// 放货设备 /// private Dictionary>> PutDevices = new(); public 机械臂() { //获取所有的机械臂 集合 var devices = Device.All.Where(v => v.HasFlag(DeviceFlags.Robot)); //开始分配 foreach (var robot in devices) { //取货设备 PickUpDevices.Add(robot.Code, robot.Sources.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => v).ToList()); PutDevices.Add(robot.Code, robot.Targets.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => new Device(v, World)).ToList()); } } public override void Do(Device obj) { #region 处理完成任务 //判断DB520 完成任务确认清除信号 是否为1 if (obj.Data.OkAck == 1 && obj.Data2 is { TaskFinishId1: 0, TaskFinishId2: 0 }) obj.Data.OkAck = 0; if (obj.Data2.TaskFinishId1 > 0 || obj.Data2.TaskFinishId2 > 0) { //处理完成的任务信息 var tasks = new List(); //开始处理 SqlSugarHelper.Do(db => { World.Log($"机械臂任务处理:开始--完成任务{obj.Data2.TaskFinishId1}--{obj.Data2.TaskFinishId2}", LogLevelEnum.Low); var isDP = obj.Entity.GetIsDirectPalletizing(db.Default); //根据DB521任务号获取对应任务 var taskInfoList = db.Default.Queryable().Where(v => v.ID == obj.Data2.TaskFinishId1 || v.ID == obj.Data2.TaskFinishId2).ToList(); foreach (var task in taskInfoList.Where(task => task.Status == Entity.TaskStatus.StackerExecution)) { //根据任务类型做不同的处理 switch (task.Type) { case TaskType.SetPlate: //工字轮入库 if (isDP) { //完成任务 task.Status = Entity.TaskStatus.ConveyorExecution; task.EndTime = DateTime.Now; db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "直接码垛任务完成码垛"); } else { //完成任务 task.Status = Entity.TaskStatus.Finish; task.EndTime = DateTime.Now; db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "入库任务结束"); } break; case TaskType.OutDepot: //var pall = db.Default.Queryable().Where(x => x.AddrTo == task.AddrTo && x.Type == TaskType.Delivery && x.Status < TaskStatus.Finish).First() ?? throw new Exception($"未找到对应的托盘搬运任务,无法进行绑盘"); task.Status = Entity.TaskStatus.StackerCompleted; task.EditTime = DateTime.Now; db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EditTime }).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "出库任务结束"); break; case TaskType.TransferDepot: task.Status = Entity.TaskStatus.Finish; task.EndTime = DateTime.Now; db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "移库任务结束"); break; } tasks.Add(task); } }); if (!tasks.Any()) throw new KnownException("数据库提交事务错误", LogLevelEnum.High); // 写入信号 obj.Data.OkAck = 1; World.Log($"机械臂任务处理:结束--完成任务{obj.Data2.TaskFinishId1}--{obj.Data2.TaskFinishId2}", LogLevelEnum.Mid); } #endregion 处理完成任务 //robot是否可以下发任务 if (obj.Data2.VoucherNo != obj.Data.VoucherNo) { World.Log($"凭证号不一致,DB520:{obj.Data.VoucherNo},DB521:{obj.Data2.VoucherNo}", LogLevelEnum.Mid); return; } if (obj.Data2.RobotMode != RobotMode.Automatic) { World.Log($"robot处于{obj.Data2.RobotMode.GetDescription()}模式", LogLevelEnum.Mid); return; } if (obj.Data2.RunStatus != RobotRunStatus.Idle) { World.Log($"robot处于{obj.Data2.RunStatus.GetDescription()}状态", LogLevelEnum.Mid); return; } //判断是否有任务是机器人执行中 //再检查是否有等待执行的货物 var inMaxQuantity = 0; //出入库的周期检查比为1:3 var taskss = new List(); var isDP = false; //当前机械臂是否直接码垛 SqlSugarHelper.Do(db => { isDP = obj.Entity.GetIsDirectPalletizing(db.Default); var code = $"RobotMaxConsecutiveStorageCount{obj.Entity.Code.Last()}"; inMaxQuantity = db.Default.Queryable().First(x => x.Code == code).SContent.ToInt(); //获取当前堆垛机的所有未完成任务 ,就算查到了未提交的事务也无所谓,无非下一个周期再执行一次 taskss = db.Default.Queryable().NoLock().Where(v => v.Status < Entity.TaskStatus.Finish && v.Device == obj.Entity.Code).ToList(); //任务集合是否有处于堆垛机执行状态的任务 if (taskss.Any(v => v.Status == Entity.TaskStatus.StackerExecution)) throw new KnownException($"有任务处于堆垛机执行状态", LogLevelEnum.High); }); if (isDP) //直接码垛 { } else { //获取入库次数 var inQuantity = obj.Entity.GetFlag("InQuantity"); //入库任务优先 或 上一个周期是出库任务并且出库任务无优先 if (inQuantity < inMaxQuantity) //入库任务 { //判断本次优先执行楼层,并设置下次执行时优先楼层 var floor = obj.Entity.GetFlag("FloorIn"); floor = floor % 2 + 1; obj.Entity.SetFlag("FloorIn", floor); obj.Entity.SetFlag("InQuantity", inQuantity + 1); //获取当前机械臂所有的取货站台 var pickUpDevices = obj.Entity.Sources.Where(x => x.HasFlag(DeviceFlags.输送机)).Where(x => x.DeviceGroup.Any()).Select( x => { var group = x.DeviceGroup.Select(s => new Device(s, World)).ToList(); return new Tuple, List>>(new Device(x, World), group); }).ToList(); if (!pickUpDevices.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无取货路径点", LogLevelEnum.High); //获取取货设备的设备组中都是停止运行的 var arrIn = pickUpDevices.Where(x => x.Item2.All(a => !a.Data.Status.HasFlag(StationStatus.Run))) .Where(x => { var inStock = x.Item2.Any(a => a.Data2.TaskNumber > 0 && a.Data.Status.HasFlag(StationStatus.PH_Status)); var minDevice = x.Item2.OrderBy(o => o.Entity.Code.ToShort()).First(); return minDevice.Data2.TaskNumber > 0 && minDevice.Data.Status.HasFlag(StationStatus.PH_Status) && minDevice.Data2.CmdType.HasFlag(StationCmd.Res7) && inStock; }).ToList(); //.OrderBy(x => x.Item1.Data2.TaskNumber) if (!arrIn.Any()) { World.Log($"[{obj.Entity.Code}]等待入库任务输送到位"); obj.Entity.SetFlag("InQuantity", inMaxQuantity + 100); //在无货物的情况下,只检查一次,下次直接查询是否有出库任务,避免无效检查周期的产生 return; } //先按可取货位数量排序,再按任务号排序 var devGroup = arrIn.OrderByDescending(x => x.Item2.Count(i => i.Data2.TaskNumber > 0 && i.Data.Status.HasFlag(StationStatus.PH_Status))) .ThenByDescending(x => { int number; List> devices = new List>(); var deviceCodes = GetDeviceCodeList(x.Item1.Entity.Code); devices = Device.All.Where(x => deviceCodes.Contains(x.Code)).Select(x => new Device(x, World)).ToList(); number = devices.Count(x => x.Data2.TaskNumber > 0 && x.Data.Status.HasFlag(StationStatus.PH_Status) && !x.Data.Status.HasFlag(StationStatus.Run)); return number; }).First().Item2 .Where(x => x.Data2.TaskNumber > 0 && x.Data.Status.HasFlag(StationStatus.PH_Status)); //可用取货位数量为1,且出库任务有优先 if (devGroup.Count() == 1 && (obj.Entity.GetFlag($"isOut-{obj.Entity.Code}") || taskss.Any(v => v.Device == obj.Entity.Code && v.Status == TaskStatus.WaitingToExecute && v.Type == TaskType.OutDepot))) { obj.Entity.SetFlag("InQuantity", inMaxQuantity + 100); //跳过入库任务执行出库任务,下次直接查询是否有出库任务,避免无效检查周期的产生 return; } if (!devGroup.Any()) { obj.Entity.SetFlag("InQuantity", inMaxQuantity + 100); //在无有效取货位的情况下,只检查一次,下次直接查询是否有出库任务,避免无效检查周期的产生 throw new KnownException($"无有效入库取货位", LogLevelEnum.High); } //如果入库任务只有一个 //等待下发的任务信息 var taskList = new List>>(); SqlSugarHelper.Do(db => { foreach (var dev in devGroup) { var task = db.Default.Queryable().First(v => v.Type == TaskType.SetPlate && v.Status == Entity.TaskStatus.FinishOfShunt && dev.Data2.TaskNumber == v.ID); if (task == null) continue; task.Status = Entity.TaskStatus.StackerExecution; task.LastInteractionPoint = dev.Entity.Code; task.SrmStation = dev.Entity.Code; task.Device = obj.Entity.Code; task.EditWho = "WCS"; db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.AddrTo, x.Line, x.Col, x.Layer, x.Depth, x.LastInteractionPoint, x.SrmStation, x.Device, x.EditWho }).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, dev.Entity.Code, task.AddrTo, "任务下发机械臂执行"); taskList.Add(new(task, dev)); } }); if (!taskList.Any()) return; switch (taskList.Count) { case 1: var task = taskList.FirstOrDefault().Item1; var dev = taskList.FirstOrDefault().Item2; //下发任务 obj.Data.TaskNumber1 = task.ID; obj.Data.SLine1 = dev.Entity.Code.ToShort(); obj.Data.SCol1 = 0; obj.Data.SLayer1 = 0; obj.Data.SDepth1 = 0; obj.Data.ELine1 = task.Line.ToShort(); obj.Data.ECol1 = task.Col.ToShort(); obj.Data.ELayer1 = task.Layer.ToShort(); obj.Data.EDepth1 = task.Depth.ToShort(); obj.Data.TaskNumber2 = 0; obj.Data.SLine2 = 0; obj.Data.SCol2 = 0; obj.Data.SLayer2 = 0; obj.Data.SDepth2 = 0; obj.Data.ELine2 = 0; obj.Data.ECol2 = 0; obj.Data.ELayer2 = 0; obj.Data.EDepth2 = 0; obj.Data.TaskSum = taskList.Count.ToShort(); obj.Data.GoodsType = task.GoodsType switch { 18 => 1, 34 => 2, 50 => 3, _ => 0 }; obj.Data.TaskType = 3; obj.Data.VoucherNo++; break; case 2: taskList = taskList.OrderBy(x => x.Item1.Depth).ToList(); //一工位取深度较大的任务 var taskInfo = taskList[1]; task = taskInfo.Item1; dev = taskInfo.Item2; obj.Data.TaskNumber1 = task.ID; obj.Data.SLine1 = dev.Entity.Code.ToShort(); obj.Data.SCol1 = 0; obj.Data.SLayer1 = 0; obj.Data.SDepth1 = 0; obj.Data.ELine1 = task.Line.ToShort(); obj.Data.ECol1 = task.Col.ToShort(); obj.Data.ELayer1 = task.Layer.ToShort(); obj.Data.EDepth1 = task.Depth.ToShort(); //二工位取深度较少的值 taskInfo = taskList[0]; task = taskInfo.Item1; dev = taskInfo.Item2; obj.Data.TaskNumber2 = task.ID; obj.Data.SLine2 = dev.Entity.Code.ToShort(); obj.Data.SCol2 = 0; obj.Data.SLayer2 = 0; obj.Data.SDepth2 = 0; obj.Data.ELine2 = task.Line.ToShort(); obj.Data.ECol2 = task.Col.ToShort(); obj.Data.ELayer2 = task.Layer.ToShort(); obj.Data.EDepth2 = task.Depth.ToShort(); obj.Data.TaskSum = taskList.Count.ToShort(); obj.Data.GoodsType = task.GoodsType switch { 18 => 1, 34 => 2, 50 => 3, _ => 0 }; obj.Data.TaskType = 3; obj.Data.VoucherNo++; break; default: throw new KnownException($"无法执行多个任务", LogLevelEnum.Mid); } World.Log($"机械臂任务处理:下发入库任务{obj.Data.TaskNumber1}--{obj.Data.TaskNumber2}--{obj.Data.VoucherNo}", LogLevelEnum.Mid); } else //出库任务 { //判断本次优先执行楼层,并设置下次执行时优先楼层 var floor = obj.Entity.GetFlag("FloorOut"); floor = floor % 2 + 1; obj.Entity.SetFlag("FloorOut", floor); obj.Entity.SetFlag("InQuantity", 0); //获取当前堆垛机所有的取货站台 var arrOut = PutDevices.First(v => v.Key == obj.Entity.Code).Value; if (!arrOut.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无放货路径点", LogLevelEnum.High); //获取可以放货的设备集合 arrOut = arrOut.Where(v => v.Data3.Status.HasFlag(StationStatus.PH_Status) && v.Data.TaskNumber == 0 && v.Data.GoodsEnd == 0).ToList();//有光电 if (!arrOut.Any()) { World.Log($"[{obj.Entity.Code}]等待出库任务输送到位"); return; } var taskInfoList = new List(); var nextAdd = ""; SqlSugarHelper.Do(db => { //所有出库点设备号,即 var allOutCode = arrOut.Select(v => new { v.Entity.Code, v.Data4.Type }).ToList(); //两个工位同时码垛,并不会一个执行一次,只有一个托盘任务全部执行完毕,才会继续执行下一个,先生成任务的码垛工位会优先执行 var taskInfos = db.Default.Queryable().NoLock().Where(v => (v.Status == TaskStatus.WaitingToExecute || v.Status == TaskStatus.ConveyorExecution) && v.Type == TaskType.OutDepot && v.Device == obj.Entity.Code) .ToList().Where(v => allOutCode.Any(x => v.SrmStation == x.Code && v.PalletType == x.Type)) .ToList(); var deliveryTask = db.Default.Queryable().Where(x => x.Status > 0 && x.Type == TaskType.Delivery).ToList().Select(x => x.AddrTo); taskInfos = taskInfos.Where(x => deliveryTask.Contains(x.SrmStation)).ToList(); if (!taskInfos.Any()) { World.Log("等待空托盘到位"); return; } if (!taskInfos.Any()) throw new KnownException($"未找到站台{JsonConvert.SerializeObject(allOutCode)}可用的出库任务", LogLevelEnum.Mid); var srmStation = taskInfos.GroupBy(x => x.SrmStation).Where(x => x.Any(s => s.Status == TaskStatus.WaitingToExecute)).Select(x => new { x.Key, x.OrderByDescending(t => t.AddTime).First().AddTime }).OrderBy(x => x.AddTime).First().Key; taskInfos = taskInfos.Where(x => x.SrmStation == srmStation).ToList(); //找到一个可以放货的待执行站台 //如果全部是待执行状态,需要验证待执行的任务的数量是否与任务总数相等 if (taskInfos.All(x => x.Status == TaskStatus.WaitingToExecute)) { var task = taskInfos.First(); if (task.FullQty != taskInfos.Count) throw new KnownException($"等待站台{srmStation}所有码垛出库任务完成初始化", LogLevelEnum.Mid); } taskInfos = taskInfos.Where(x => x.Status == TaskStatus.WaitingToExecute).OrderBy(x => x.ProdLine).ToList(); if (taskInfos.FirstOrDefault().WarehouseCode.Contains("S")) //如果是南侧,翻转排序 { taskInfos = taskInfos.OrderByDescending(x => x.ProdLine).ToList(); } var surplusTaskNumber = taskInfos.Count; //剩余任务数量 taskInfos = taskInfos.Take(2).ToList(); var warehouseCode = taskInfos.FirstOrDefault().WarehouseCode; var exTaskNumber = taskInfos.Count;//执行任务数量 surplusTaskNumber -= exTaskNumber; if (exTaskNumber == 2) //有两个任务 { var minDepth = taskInfos!.MinBy(x => x.Depth); var maxDepth = taskInfos.MaxBy(x => x.Depth); //产品类型不同时,只能取一个 if (minDepth.GoodsType != maxDepth.GoodsType) { //南边取位号较大的,北边取位号较小的 taskInfos = warehouseCode.Contains("S") ? taskInfos.OrderByDescending(x => x.ProdLine).Take(1).ToList() : taskInfos.OrderBy(x => x.ProdLine).Take(1).ToList(); } //深度之和等于6(机械臂当前无法同时执行两个三深度的取货任务) else if (taskInfos.Sum(x => x.Depth) == 6) { taskInfos = warehouseCode.Contains("S") ? taskInfos.OrderByDescending(x => x.ProdLine).Take(1).ToList() : taskInfos.OrderBy(x => x.ProdLine).Take(1).ToList(); } else if (taskInfos[0].SrmStation != taskInfos[1].SrmStation) { taskInfos = warehouseCode.Contains("S") ? taskInfos.OrderByDescending(x => x.ProdLine).Take(1).ToList() : taskInfos.OrderBy(x => x.ProdLine).Take(1).ToList(); } else if (warehouseCode.Contains("S")) { //从大到小 一抓偶数 var max = taskInfos.MaxBy(x => x.ProdLine).ProdLine; if ((max & 1) == 1) //抓一不是偶数 { taskInfos = taskInfos.OrderByDescending(x => x.ProdLine).Take(1).ToList(); } } else if (warehouseCode.Contains("N")) { //从小到达 一抓奇数 var mix = taskInfos.MinBy(x => x.ProdLine).ProdLine; if ((mix & 1) == 0) //抓一不是奇数 { taskInfos = taskInfos.OrderBy(x => x.ProdLine).Take(1).ToList(); } } } #region 计算剩余可执行任务数 //如果有两个任务,且只有一个任务可以执行,剩余任务数+1 if (exTaskNumber == 2 && taskInfoList.Count == 1) surplusTaskNumber += 1; if (surplusTaskNumber >= 1) obj.Entity.SetFlag($"isOut-{obj.Entity.Code}", true); //剩余任务数大于或等于1,下次满足条件时可以优先执行出库任务 else obj.Entity.SetFlag($"isOut-{obj.Entity.Code}", false); //剩余任务数等于或小于0,下次满足条件时不可以优先执行出库任务 #endregion 计算剩余可执行任务数 foreach (var task in taskInfos) { task.Status = Entity.TaskStatus.StackerExecution; task.LastInteractionPoint = task.Device; task.StartTime = DateTime.Now; task.EditWho = "WCS"; nextAdd = task.SrmStation; db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.LastInteractionPoint, x.StartTime, x.EditWho }).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.Device, task.SrmStation, "任务下发机械臂执行"); taskInfoList.Add(task); } }); if (!taskInfoList.Any()) return; switch (taskInfoList.Count) { case 1: var task = taskInfoList.FirstOrDefault(); //下发任务 obj.Data.TaskNumber1 = task.ID; obj.Data.SLine1 = task.Line.ToShort(); obj.Data.SCol1 = task.Col.ToShort(); obj.Data.SLayer1 = task.Layer.ToShort(); obj.Data.SDepth1 = task.Depth.ToShort(); obj.Data.ELine1 = nextAdd.ToShort(); obj.Data.ECol1 = task.ProdLine; obj.Data.ELayer1 = 0; obj.Data.EDepth1 = 0; obj.Data.TaskNumber2 = 0; obj.Data.SLine2 = 0; obj.Data.SCol2 = 0; obj.Data.SLayer2 = 0; obj.Data.SDepth2 = 0; obj.Data.ELine2 = 0; obj.Data.ECol2 = 0; obj.Data.ELayer2 = 0; obj.Data.EDepth2 = 0; obj.Data.TaskSum = taskInfoList.Count.ToShort(); obj.Data.GoodsType = task.GoodsType switch { 18 => 1, 34 => 2, 50 => 3, _ => 0 }; obj.Data.TaskType = 4; obj.Data.VoucherNo++; break; case 2: taskInfoList = taskInfoList.OrderBy(x => x.Depth).ToList(); //一工位取深度较大的任务 var taskInfo = taskInfoList[1]; obj.Data.TaskNumber1 = taskInfo.ID; obj.Data.SLine1 = taskInfo.Line.ToShort(); obj.Data.SCol1 = taskInfo.Col.ToShort(); obj.Data.SLayer1 = taskInfo.Layer.ToShort(); obj.Data.SDepth1 = taskInfo.Depth.ToShort(); obj.Data.ELine1 = nextAdd.ToShort(); obj.Data.ECol1 = taskInfo.WarehouseCode.Contains("S") ? taskInfoList.Max(x => x.ProdLine) : taskInfoList.Min(x => x.ProdLine); obj.Data.ELayer1 = 0; obj.Data.EDepth1 = 0; //二工位取深度较少的值 taskInfo = taskInfoList[0]; obj.Data.TaskNumber2 = taskInfo.ID; obj.Data.SLine2 = taskInfo.Line.ToShort(); obj.Data.SCol2 = taskInfo.Col.ToShort(); obj.Data.SLayer2 = taskInfo.Layer.ToShort(); obj.Data.SDepth2 = taskInfo.Depth.ToShort(); obj.Data.ELine2 = nextAdd.ToShort(); obj.Data.ECol2 = taskInfo.WarehouseCode.Contains("S") ? taskInfoList.Min(x => x.ProdLine) : taskInfoList.Max(x => x.ProdLine); obj.Data.ELayer2 = 0; obj.Data.EDepth2 = 0; obj.Data.TaskSum = taskInfoList.Count.ToShort(); obj.Data.GoodsType = taskInfo.GoodsType switch { 18 => 1, 34 => 2, 50 => 3, _ => 0 }; obj.Data.TaskType = 4; obj.Data.VoucherNo++; break; default: throw new KnownException($"无法执行多个任务", LogLevelEnum.Mid); } World.Log($"机械臂任务处理:下发出库任务{obj.Data.TaskNumber1}--{obj.Data.TaskNumber2}--{obj.Data.VoucherNo}", LogLevelEnum.Mid); } } } public override bool Select(Device dev) { return dev.Code is "Robot1" or "Robot2" or "Robot3" or "Robot4" or "Robot5" or "Robot6"; } public List GetDeviceCodeList(string code) { return code switch { "424" => new List() { "424", "425", "422", "426", "427" }, "433" => new List() { "433", "434", "431", "435", "436" }, "442" => new List() { "442", "443", "440", "444", "445" }, "642" => new List() { "642", "643", "640", "644", "645" }, "633" => new List() { "633", "634", "631", "635", "636" }, "624" => new List() { "624", "625", "622", "226", "627" }, "824" => new List() { "824", "825", "822", "826", "827" }, "833" => new List() { "833", "834", "831", "835", "836" }, "842" => new List() { "842", "843", "840", "844", "845" }, "1042" => new List() { "1042", "1043", "1040", "1044", "1045" }, "1033" => new List() { "1033", "1034", "1031", "1035", "1036" }, "1024" => new List() { "1024", "1025", "1022", "1026", "1027" }, "1224" => new List() { "1224", "1225", "1222", "1226", "1227" }, "1233" => new List() { "1233", "1234", "1231", "1235", "1236" }, "1242" => new List() { "1242", "1243", "1240", "1244", "1245" }, "1442" => new List() { "1442", "1443", "1440", "1444", "1445" }, "1433" => new List() { "1433", "1434", "1431", "1435", "1436" }, "1424" => new List() { "1424", "1425", "1422", "1426", "1427" }, _ => new List() }; } } }