/** * Создание ошибки, содержащей элемент диаграммы */ public static void createMistake(Level level, string mistake, ADNodesList.ADNode element, ALL_MISTAKES type) { if (diagram == null) { return; } var tmp = (DiagramElement)element.getValue(); string descr = tmp is DecisionNode ? ((DecisionNode)tmp).getQuestion() : tmp.getDescription(); var bbox = new BoundingBox(tmp.X, tmp.Y, tmp.Width, tmp.Height); descr = descr == ""?descr:(" '" + descr + "'"); diagram.Mistakes.Add(new Mistake(levelAdapter(level), ElementTypeAdapter.toString(tmp.getType()) + descr + ": " + mistake, bbox, type)); }
/** * Проверка был ли данный элемент раннее активирован. Если да, то проверка завершается */ private bool wasAlreadyActive(int tokenIndex, List <List <Token> > stepResultMasks, ADNodesList.ADNode curNode) { foreach (List <Token> stepResultMask in stepResultMasks) { if (stepResultMask[tokenIndex].type != NO_TOKEN) { if (curNode.getValue().getType() != ElementType.FINAL_NODE) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.TWO_TOKENS], MistakeAdapter.toString(MISTAKES.TWO_TOKENS), ALL_MISTAKES.TWO_TOKENS); } else { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.MANY_TOKENS_IN_END], MistakeAdapter.toString(MISTAKES.MANY_TOKENS_IN_END), ALL_MISTAKES.MANY_TOKENS_IN_END); } return(true); } } return(false); }
private List <Token> activateJoin(ADNodesList.ADNode joinNode, List <Token> mask, List <List <Token> > resultMasks, List <int> curColors) { List <Token> newMask = copyMask(mask); List <Token> maskCur = copyMask(mask); int color = 0; int curIndex = ((DiagramElement)joinNode.getValue()).petriId; List <int> idsPrev = new List <int>(); // список ид элементов перед join List <int> newColors = new List <int>(curColors); newColors.RemoveAt(newColors.Count - 1); // подготовили список цветов для join // все предшествующие элементы должны содержать токен одного цвета for (int i = 0; i < joinNode.prevSize(); i++) { int idPrev = ((DiagramElement)joinNode.getPrev(i).getValue()).petriId; idsPrev.Add(idPrev); if (newMask[idPrev].type == NO_TOKEN) { return(null); } if (i == 0) { color = newMask[idPrev].peekLastColor(); } if (newMask[idPrev].peekLastColor() != color) { return(null); } } // если все предыдущие элементы были активны, активируем текущий // для каждой результирующей маски шага удаляем токены и добавляем токен в join foreach (int id in idsPrev) { updateStepMasks(id, curIndex, resultMasks, newColors); setNewEmptyToken(maskCur, id); // удаляем токены из маски шага } return(maskCur); }
public void check(ADNodesList adList) { Queue <List <Token> > leaves = new Queue <List <Token> >(); // необработанные маски HashSet <string> masksInUsed = new HashSet <string>(adList.getPetriElementsCount()); // использованные маски // ищем начальное состояние ADNodesList.ADNode initNode = adList.findInitial(); var finalNode = adList.findFinal(); var indexesOfFinalNode = finalNode.Select(x => ((DiagramElement)x.getValue()).petriId).ToList(); // создаем маску и добавляем ее в необработанные List <Token> maskTmp = createEmptyMask(adList.getPetriElementsCount()); setNewPaleToken(maskTmp, ((DiagramElement)initNode.getValue()).petriId); leaves.Enqueue(maskTmp); masksInUsed.Add(maskToString(maskTmp)); // добавляем в множество использованных bool canReachFinal = false; List <List <Token> > stepResultMasks = new List <List <Token> >(); // содержит маски, кот могут получиться на каждом шаге string originMaskString = ""; // главный цикл прохода по всем элементам, участвующих в проверке while (leaves.Count > 0) { List <Token> originMask = leaves.Dequeue(); // берем первую маску originMaskString = maskToString(originMask); stepResultMasks.Clear(); List <Token> stepMask = copyMask(originMask); // маска, которую будем изменять по мере деактивации токенов stepResultMasks.Add(copyMask(stepMask)); // Если список масок не изменится, то будет тупик, тк текущая маска уже добавлена в использованные int i = 0; // Console.WriteLine("Or: " + maskToString(originMask)); // проходим по всем элементам маски, находим активированные // и проверяем, можно ли активировать следующий элемент for (int stepProhod = 0; stepProhod < 2; stepProhod++) // сначала проходим по условным, затем по остальным эл-м { i = 0; while (i < stepMask.Count) { if (stepProhod == 0 && adList.getNodeByPetriIndex(i).getValue().getType() != ElementType.DECISION) { i++; continue; // интересуют только эл-ты, содержащие токены на данном шаге } if (stepProhod == 0 && adList.getNodeByPetriIndex(i).getValue().getType() == ElementType.DECISION && stepMask[i].type != TOKEN) { i++; continue; // интересуют только эл-ты, содержащие токены на данном шаге } if (stepProhod == 1 && stepMask[i].type != TOKEN) { i++; continue; // интересуют только эл-ты, содержащие токены на данном шаге } // нашли активный элемент ADNodesList.ADNode curNode = adList.getNodeByPetriIndex(i); //индекс в списке совпадает с петри ид эл-та int curNodeIndex = ((DiagramElement)curNode.getValue()).petriId; List <int> colorsCurToken = new List <int>(stepMask[curNodeIndex].colors); // особо обрабатываем ситуации, когда элемент имеет несколько выходных переходов if (curNode.nextSize() > 1) { // если эл-т разветвитель, то последующее состояние единственно, однако надо установить несколько токенов за раз if (curNode.getValue().getType() == ElementType.FORK) { colorsCurToken.Add(generateRandomColor()); // активируем все следующие элементы for (int j = 0; j < curNode.nextSize(); j++) { // сразу после форка не может быть join'a, поэтому все эл-ты будут активированы int indexOfNewToken = ((DiagramElement)curNode.getNext(j).getValue()).petriId; // проверка, что эл-т не был раннее активирован if (wasAlreadyActive(indexOfNewToken, stepResultMasks, curNode.getNext(j))) { return; } // изменяем существующие результирующие маски updateStepMasks(((DiagramElement)curNode.getValue()).petriId, indexOfNewToken, stepResultMasks, colorsCurToken); } setNewEmptyToken(stepMask, curNodeIndex); } // если это условный оператор, то он порождает несколько возможных последующих состояний else { List <List <Token> > decisionMasks = new List <List <Token> >(); // содержит все возможные маски вариантов перемещения токена bool tokenWasRemoved = false; // активируем следующие элементы по одному for (int j = 0; j < curNode.nextSize(); j++) { int indexOfNewToken = ((DiagramElement)curNode.getNext(j).getValue()).petriId; // индекс активируемого эл-та // проверка, что эл-т не был раннее активирован if (wasAlreadyActive(indexOfNewToken, stepResultMasks, curNode.getNext(j))) { return; } // Join обрабатывается с помощью reverse проверки if ((curNode.getNext(j).getValue()).getType() == ElementType.JOIN) { List <List <Token> > temp = copyMasks(stepResultMasks); List <Token> result = activateJoin(curNode.getNext(j), stepMask, temp, colorsCurToken); if (result != null) { stepMask = result; decisionMasks.AddRange(temp); tokenWasRemoved = true; } } else { // в каждой существующей результирующей маске меняем токен и сохраняем в промежуточный список // в итоге получится новый список, содержащий несколько вариантов результирующих масок, // в каждом из которых создан новый токен в зависимости от активированного следующего эл-та foreach (List <Token> resultMask in stepResultMasks) { List <Token> temp = copyMask(resultMask); setToken(temp, indexOfNewToken, NEW_TOKEN, colorsCurToken); // добавляем новый токен setNewEmptyToken(temp, curNodeIndex); // удаляем токен текущего эл-та decisionMasks.Add(temp); tokenWasRemoved = true; } } } // изменяем маску шага и список результирующих масок, если токен был удален if (tokenWasRemoved) { setNewEmptyToken(stepMask, ((DiagramElement)curNode.getValue()).petriId); // меняем результирующую маску stepResultMasks = decisionMasks; } } } else // если выходной переход один { int indexOfNewToken = ((DiagramElement)curNode.getNext(0).getValue()).petriId; // проверка, что эл-т не был раннее активирован if (wasAlreadyActive(indexOfNewToken, stepResultMasks, curNode.getNext(0))) { return; } // если следующий Join if ((curNode.getNext(0).getValue()).getType() == ElementType.JOIN) { List <Token> result = activateJoin(curNode.getNext(0), stepMask, stepResultMasks, colorsCurToken); if (result != null) { stepMask = result; } } else { updateStepMasks(((DiagramElement)curNode.getValue()).petriId, indexOfNewToken, stepResultMasks, colorsCurToken); setNewEmptyToken(stepMask, curNodeIndex); } } i++; } } // в результирующих масках заменяем NEW_Token на TOKEN foreach (List <Token> stepResultMask in stepResultMasks) { stepResultMask.ForEach(x => x.type = x.type == NEW_TOKEN ? TOKEN : x.type); //Console.WriteLine("Re: " + maskToString(stepResultMask)); if (originMaskString == maskToString(stepResultMask)) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.DEAD_ROAD], MistakeAdapter.toString(MISTAKES.DEAD_ROAD), ALL_MISTAKES.DEAD_ROAD); //Console.WriteLine("Again?: "+originMaskString); return; } } // проверяем, что новой маски нет во множестве обработанных и добавляем в необработанные в таком случае foreach (List <Token> resultMask in stepResultMasks) { if (!findInMasksInUsed(masksInUsed, resultMask)) { int indexOfFinalNode = -1; // проверяем, не достигли ли конечной маркировки (существует путь позволяющий добраться хоть до какого-н finalNode) foreach (var ind in indexesOfFinalNode) { if (resultMask[ind].type == TOKEN) { indexOfFinalNode = ind; break; } } if (indexOfFinalNode != -1) { canReachFinal = true; if (resultMask[indexOfFinalNode].peekLastColor() != NO_COLOR) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.FINAL_COLOR_TOKEN], MistakeAdapter.toString(MISTAKES.FINAL_COLOR_TOKEN), ALL_MISTAKES.FINAL_COLOR_TOKEN); return; } //Проверка, что не осталось токенов int tokenCount = 0; for (int j = 0; j < resultMask.Count && tokenCount <= 1; j++) { if (resultMask[j].type == TOKEN) { tokenCount++; } } if (tokenCount > 1) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.MANY_TOKENS_IN_END], MistakeAdapter.toString(MISTAKES.MANY_TOKENS_IN_END), ALL_MISTAKES.MANY_TOKENS_IN_END); return; } } else { leaves.Enqueue(copyMask(resultMask)); } masksInUsed.Add(maskToString(resultMask)); // добавляем полученную маску в множество обработанных } } } // проверяем, что конечное состояние было достигнуто if (!canReachFinal) { ADMistakeFactory.createMistake(MistakesSeriousness.mistakes[MISTAKES.COULD_NOT_REACH_FINAL], MistakeAdapter.toString(MISTAKES.COULD_NOT_REACH_FINAL), ALL_MISTAKES.COULD_NOT_REACH_FINAL); } }