Jump to content

Acanis

Active Members
  • Posts

    50
  • Joined

  • Last visited

Recent Profile Visitors

324 profile views

Acanis's Achievements

  1. I still dont understand everything, but working on it I reduced the global variables, put all the stuff into an function and renamed a lot of the variables. Maybe its worse for experienced eyes, but it helps me a lot It seems that after the refactoring everything still works as before and I was able to customize it so that the drawing function can be used again without further customization. Ill play around with the parameters and compare the solutions with the one of my own try; but it feels pretty good for the example data :)! Ill post the updated code, so other interested people can use it
  2. Hehe, Iam german and your right... But I try to improve The grid stuff is really old and I got some help of a more experienced programmer to finish it... ^^ (And I liked it, because it was there and understandable for me^^) ChatGPT did help me with the visualisation, because I never used GDI+ before ^^ I try to annotate my code, but ChatGPT did help, too I planned the desired number of intermediate points to be an input to the function. But if Iam able to understand your code, Ill try to change that myself. In any case, MANY THANKS in advance! Ill add the visualisation stuff later and test it a lot to understand the code and the impact of the parameters. Really cool!
  3. Hey, thanks for providing examples I would really like to understand, how TSP works (in AutoIt). I wanted to try to adapt it to a script of mine, but I find it difficult to follow the example and replace individual parts. Since the cities are global and everything is too connected and the variable names are also a bit hard to read for me. (I am not a very experienced hobby developer^^) I created a script with a more complicated coordinate system using ChatGPT and a lot of time and implemented a "nearest neighbor" algo. To make it a bit better with my limited knowledge, I tried to use it at least twice, hoping that the script wouldn't do something really stupid at least at the first step. My hope was somewhat that the "understanding" of the coordinate system is mainly in the calculation of the distance and then I can simply adjust the input (the cities) and replace the function for calculating the distance and then I would be able to progress step by step somehow. But that doesn't work with the structure of the example and since my understanding is running close to the limit, I can't really make any progress or even get started. Could someone perhaps help me? I think my example code and the visualization could be used to make the TSP example more comprehensible (using visible coordinates and with this kind of visualisation)... I would be really grateful ^^! My code: #include <Array.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <GDIPlus.au3> #include <EditConstants.au3> Global $iMapWidth = 60, $iMapHeight = 60, $iMapRoot = 3 ; Beispielkoordinaten Local $aInputArray = ["2:50:9", "2:50:2", "2:50:4", "1:50:3", "1:50:8", "1:49:8", "3:49:4", "3:51:3", "3:51:8", "2:51:7", "1:51:4", "2:48:8", "2:48:4", "1:48:3", "1:48:2", "1:48:1", "3:48:4", "4:49:4", "3:50:6", "4:50:4", "4:50:5", "5:51:1"] Local $sStartCoordinate = "3:51:1" Local $sHomeCoordinate = "2:50:8" ;~ Local $aBestRoute = getBestRoute($sStartCoordinate, $aInputArray, 5) Local $aBestRoute = getBestRoute($sStartCoordinate, $aInputArray, 5, $sHomeCoordinate) DrawMap($aInputArray, $sStartCoordinate, $aBestRoute, $aBestRoute[UBound($aBestRoute) - 1]) Func getBestRoute($sStartCoordinate, $aTargets, $iNumberOfTargets, $sHomeCoordinate = False) Local $aBestRoutes[10], $aBestRoute[0] Local $sEndCoordinate = $sHomeCoordinate ? $sHomeCoordinate : $sStartCoordinate Local $aPossibleFirstTargets = getNearestTargets($sStartCoordinate, $aTargets) Local $aTargetsWithoutStartC = $aTargets Local $iIdStartCoordInTargets = _ArraySearch($aTargets, $sStartCoordinate) ; Falls ein Ziel auch der Startpunkt ist If $iIdStartCoordInTargets >= 0 Then _ArrayDelete($aTargetsWithoutStartC, $iIdStartCoordInTargets) ; Wenn Ziel auch Startpunkt, darf das nicht für die Suche des weiteren Weges genutzt werden ; Finde mit den neuen Startkoordinaten die besten Wege For $i = 0 To UBound($aPossibleFirstTargets) - 1 $aBestRoutes[$i] = getShortRoute($aPossibleFirstTargets[$i], $aTargetsWithoutStartC, $iNumberOfTargets - 1, $sEndCoordinate) Next ; Lösche leere Einträge, falls es weniger als 10 Ziele gab For $i = UBound($aBestRoutes) - 1 To 0 Step -1 If $aBestRoutes[$i] = "" Then _ArrayDelete($aBestRoutes, $i) EndIf Next ; Finde die beste Route Local $iShortestDistance = -1 For $i = 0 To UBound($aBestRoutes) - 1 Local $aTemp = $aBestRoutes[$i] $aTemp[1] += getDistance($sStartCoordinate, $aTemp[2]) Local $iTotalDistance = $aTemp[1] ; Vergleiche die Gesamtentfernung mit der bisher kürzesten Route If $iShortestDistance = -1 Or $iTotalDistance < $iShortestDistance Then $iShortestDistance = $iTotalDistance $aBestRoute = $aTemp ; Aktuelle Route als beste Route speichern EndIf Next _ArrayInsert($aBestRoute, 2, $sStartCoordinate) Return $aBestRoute ; Die kürzeste Route wird zurückgegeben EndFunc ; Finde die bis zu 10 nächsten Koordinaten, die alle potenziell gute Start-Koordinaten für die weitere Suche wären Func getNearestTargets($sStartCoordinate, $aTargets) Local $aNearestTargets[0] Local $iMaxTargets = UBound($aTargets) > 10 ? 10 : UBound($aTargets) For $i = 1 To $iMaxTargets Local $iShortestDistance = -1 Local $sNearestTarget = "" For $j = 0 To UBound($aTargets) - 1 Local $iDistance = getDistance($sStartCoordinate, $aTargets[$j]) If $iShortestDistance = -1 Or $iDistance < $iShortestDistance Then $iShortestDistance = $iDistance $sNearestTarget = $aTargets[$j] EndIf Next If $sNearestTarget <> "" Then _ArrayAdd($aNearestTargets, $sNearestTarget) _ArrayDelete($aTargets, _ArraySearch($aTargets, $sNearestTarget)) EndIf Next Return $aNearestTargets EndFunc Func getShortRoute($sStartCoordinate, $aInputArray, $iNumberOfTargets, $sEndCoordinate) Local $aVisited[0] ; Leeres Array für besuchte Ziele Local $iTotalDistance = 0 Local $sCurrentCoordinate = $sStartCoordinate Local $iVisitedTargets = 0 _ArrayAdd($aVisited, $sStartCoordinate) ; Ist visited, weil das hier ja mit NearestTargets arbeitet, also schon das erste Ziel nach der echten Startkoordinate ist Local $iIdOfStartCoordinateInInput = _ArraySearch($aInputArray, $sStartCoordinate) If $iIdOfStartCoordinateInInput >= 0 Then _ArrayDelete($aInputArray, $iIdOfStartCoordinateInInput) ; Startkoordinate aus Array für mögliche Ziele entfernen, weil hier dann schon abgelaufen als wirklich erstes Ziel! For $i = 1 To $iNumberOfTargets Local $iShortestDistance = -1 Local $sNextCoordinate = "" Local $iNextIndex = -1 For $j = 0 To UBound($aInputArray) - 1 If Not _ArraySearch($aVisited, $aInputArray[$j]) >= 0 Then Local $iDistance = getDistance($sCurrentCoordinate, $aInputArray[$j]) If $iShortestDistance == -1 Or $iDistance < $iShortestDistance Then $iShortestDistance = $iDistance $sNextCoordinate = $aInputArray[$j] $iNextIndex = $j EndIf EndIf Next If $iNextIndex <> -1 Then $iTotalDistance += $iShortestDistance $sCurrentCoordinate = $sNextCoordinate _ArrayAdd($aVisited, $sNextCoordinate) _ArrayDelete($aInputArray, $iNextIndex) $iVisitedTargets += 1 Else ; Kein weiteres Ziel gefunden, brechen Sie die Schleife ab ExitLoop EndIf Next $iTotalDistance += getDistance($aVisited[UBound($aVisited) -1], $sEndCoordinate) ; Erstellen Sie das Ergebnisarray Local $aResult[2] = [$iVisitedTargets + 1, $iTotalDistance] ; +1, da die Startkoordiante nicht als besuchtes Ziel gilt For $i = 0 To $iVisitedTargets _ArrayAdd($aResult, $aVisited[$i]) Next _ArrayAdd($aResult, $sEndCoordinate) Return $aResult EndFunc Func DrawMap($aInputArray, $sStartCoordinate, $aBestRoute, $sEndCoordinate) Local $iGridSize = 20 Local $iGuiWidth = 900 Local $iGuiHeight = 900 Local $iLineSpacing = $iGuiWidth / $iGridSize ; Berechnen des Abstands zwischen den Linien ; GDI+ initialisieren _GDIPlus_Startup() ; GUI erstellen Local $hGUI = GUICreate("Map Visualization", $iGuiWidth, $iGuiHeight) GUISetState(@SW_SHOW) ; Grafikobjekt erstellen Local $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI) Local $hBrushOrange = _GDIPlus_BrushCreateSolid(0xFFFFA500) ; Orange Local $hBrushRed = _GDIPlus_BrushCreateSolid(0xFFFF0000) ; Rot Local $hBrushBlack = _GDIPlus_BrushCreateSolid(0xFF000000) ; Schwarz Local $hBrushGrey = _GDIPlus_BrushCreateSolid(0xFF008000) ; Grau Local $hPen = _GDIPlus_PenCreate(0xFF000000, 1) ; Schwarzer Stift mit einer Breite von 1 für das Gitter ; Arrays mit 2D-Koordinaten erstellen Local $aInputArray2D[0] Local $aBestRoute2D[0] For $i = 0 To UBound($aInputArray) - 1 _ArrayAdd($aInputArray2D, convertCoordTo2D($aInputArray[$i])) Next For $i = 2 To UBound($aBestRoute) - 1 _ArrayAdd($aBestRoute2D, convertCoordTo2D($aBestRoute[$i])) Next Local $sMiddle2D = $iGridSize / 2 Local $aStartCoordinate2D = StringSplit(convertCoordTo2D($sStartCoordinate), ':', 2) Local $aEndCoordinate2D = StringSplit(convertCoordTo2D($sEndCoordinate), ':', 2) Local $iXDifference = $aStartCoordinate2D[0] - $sMiddle2D Local $iYDifference = $aStartCoordinate2D[1] - $sMiddle2D For $i = 1 To $iMapWidth * $iMapRoot For $j = 1 To $iMapHeight * $iMapRoot ; Überprüfen Sie, ob die Koordinate in der besten Route ist If _ArraySearch($aBestRoute2D, $i & ":" & $j) >= 0 Then Local $iRouteIndex = _ArraySearch($aBestRoute2D, $i & ":" & $j) If $iRouteIndex >= 1 Then ; Beachten Sie den Index 1, um den ersten Zielpunkt einzubeziehen _GDIPlus_GraphicsFillRect($hGraphic, ($i - 1 - $iXDifference) * $iLineSpacing, ($j - 1 - $iYDifference) * $iLineSpacing, $iLineSpacing, $iLineSpacing, $hBrushRed) ; Beschriftung mit der Reihenfolge hinzufügen _GDIPlus_GraphicsDrawString($hGraphic, $iRouteIndex & "", ($i - 1 - $iXDifference) * $iLineSpacing + 5, ($j - 1 - $iYDifference) * $iLineSpacing + 5, "Arial", 10, 0, 0xFFFFFFFF) EndIf ElseIf _ArraySearch($aInputArray2D, $i & ":" & $j) >= 0 Then ;~ ConsoleWrite("Zeichnen aus InputArray:" & @CRLF & $i & ":" & $j & " | " & $aInputArray[_ArraySearch($aInputArray2D, $i & ":" & $j)] & @CRLF) ; Koordinate im InputArray, aber nicht in der besten Route _GDIPlus_GraphicsFillRect($hGraphic, ($i - 1 - $iXDifference) * $iLineSpacing, ($j - 1 - $iYDifference) * $iLineSpacing, $iLineSpacing, $iLineSpacing, $hBrushOrange) EndIf ; Endpunkt zeichnen, wenn er nicht die Start-Koordinate ist If Not _2DCoordArraysEqual($aStartCoordinate2D, $aEndCoordinate2D) And _2DCoordStringsEqual($i & ":" & $j, convertCoordTo2D($sEndCoordinate)) Then _GDIPlus_GraphicsFillRect($hGraphic, ($i - 1 - $iXDifference) * $iLineSpacing, ($j - 1 - $iYDifference) * $iLineSpacing, $iLineSpacing, $iLineSpacing, $hBrushGrey) ; "FIN" in die Koordinaten schreiben _GDIPlus_GraphicsDrawString($hGraphic, "FIN", ($i - 1 - $iXDifference) * $iLineSpacing + 5, ($j - 1 - $iYDifference) * $iLineSpacing + 5, "Arial", 10, 0, 0xFFFFFFFF) EndIf Next Next ; Startpunkt zeichnen und die Länge des Lösung angebe _GDIPlus_GraphicsFillRect($hGraphic, ($sMiddle2D - 1) * $iLineSpacing, ($sMiddle2D - 1) * $iLineSpacing, $iLineSpacing, $iLineSpacing, $hBrushBlack) _GDIPlus_GraphicsDrawString($hGraphic, $aBestRoute[1], ($sMiddle2D - 1) * $iLineSpacing + 10, ($sMiddle2D - 1) * $iLineSpacing + 15, "Arial", 12, 0, 0xFFFFFFFF) ; Gitter zeichnen For $i = 1 To $iGridSize For $j = 1 To $iGridSize _GDIPlus_GraphicsDrawRect($hGraphic, ($i - 1) * $iLineSpacing, ($j - 1) * $iLineSpacing, $iLineSpacing, $iLineSpacing, $hPen) Next Next ; GUI anzeigen GUISetState(@SW_SHOW, $hGUI) ; Loop bis der Benutzer die Anwendung schließt. Do Until GUIGetMsg() = $GUI_EVENT_CLOSE ; Ressourcen aufräumen CleanupResources($hBrushOrange, $hBrushRed, $hBrushBlack, $hPen, $hGraphic, $hGUI) EndFunc Func CleanupResources($hBrushOrange, $hBrushRed, $hBrushBlack, $hPen, $hGraphic, $hGUI) _GDIPlus_BrushDispose($hBrushOrange) _GDIPlus_BrushDispose($hBrushRed) _GDIPlus_BrushDispose($hBrushBlack) _GDIPlus_PenDispose($hPen) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() GUIDelete($hGUI) EndFunc Func _2DCoordArraysEqual($coord1, $coord2) ; Überprüfen, ob beide Parameter Arrays sind If IsArray($coord1) And IsArray($coord2) Then ; Überprüfen Sie die Anzahl der Elemente in beiden Arrays If UBound($coord1) <> UBound($coord2) Then Return False EndIf ; Vergleichen Sie die Werte in den Arrays For $i = 0 To UBound($coord1) - 1 If $coord1[$i] <> $coord2[$i] Then Return False EndIf Next ; Wenn alle Vergleiche erfolgreich sind, geben Sie True zurück Return True EndIf ; Wenn keiner der obigen Fälle zutrifft, geben Sie False zurück Return False EndFunc Func _2DCoordStringsEqual($coord1, $coord2) ; Zerlegen Sie die Koordinaten in Arrays Local $aCoord1 = StringSplit($coord1, ':') Local $aCoord2 = StringSplit($coord2, ':') ; Überprüfen Sie die Anzahl der Elemente in beiden Arrays If UBound($aCoord1) <> UBound($aCoord2) Then Return False EndIf ; Vergleichen Sie die Werte in den Arrays For $i = 1 To UBound($aCoord1) - 1 If $aCoord1[$i] <> $aCoord2[$i] Then Return False EndIf Next ; Wenn alle Vergleiche erfolgreich sind, geben Sie True zurück Return True EndFunc Func convertCoordTo2D($sCoord) $aCoord = getArrayFromCoordString($sCoord) Local $ax = ($aCoord[0][0] - 1) * $iMapRoot + Mod($aCoord[0][2] - 1, $iMapRoot) + 1 Local $ay = ($aCoord[0][1] - 1) * $iMapRoot + Int(($aCoord[0][2] - 1)/$iMapRoot) + 1 Return $ax & ":" & $ay EndFunc Func convert2DTo3D($sCoord) Local $aCoord = StringSplit($sCoord, ':', 2) Local $ax = $aCoord[0] Local $ay = $aCoord[1] Local $ar = Mod(($ax - 1), $iMapRoot) + 1 + Mod(($ay - 1), $iMapRoot) * $iMapRoot Local $axx = Ceiling($ax / $iMapRoot) Local $ayy = Ceiling($ay / $iMapRoot) Return $axx & ":" & $ayy & ":" & $ar EndFunc Func getStringFromArrayCoord($aArray) Return $aArray[0][0] & ":" & $aArray[0][1] & ":" & $aArray[0][2] EndFunc Func getArrayFromCoordString($sString) Local $aTmp1 = StringSplit($sString, ':', 2) Local $aCoord[1][3] = [[$aTmp1[0], $aTmp1[1], $aTmp1[2]]] Return $aCoord EndFunc Func getDistance($sStart, $sTarget) Local $aDist[9] ; If the start and destination are the same, the distance is 1 If StringCompare($sStart, $sTarget) = 0 Then Return 1 Local $aTmp1 = getArrayFromCoordString($sStart), $aTmp2 = getArrayFromCoordString($sTarget) Local $x1 = Int($aTmp1[0][0]), $y1 = Int($aTmp1[0][1]), $r1 = Int($aTmp1[0][2]) Local $x2 = Int($aTmp2[0][0]), $y2 = Int($aTmp2[0][1]), $r2 = Int($aTmp2[0][2]) $aDist[0] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2 - $iMapWidth) & ':' & ($y2 - $iMapHeight) & ':' & ($r2)) $aDist[1] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2 - $iMapWidth) & ':' & ($y2) & ':' & ($r2)) $aDist[2] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2 - $iMapWidth) & ':' & ($y2 + $iMapHeight) & ':' & ($r2)) $aDist[3] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2) & ':' & ($y2 - $iMapHeight) & ':' & ($r2)) $aDist[4] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2) & ':' & ($y2) & ':' & ($r2)) $aDist[5] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2) & ':' & ($y2 + $iMapHeight) & ':' & ($r2)) $aDist[6] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2 + $iMapWidth) & ':' & ($y2 - $iMapHeight) & ':' & ($r2)) $aDist[7] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2 + $iMapWidth) & ':' & ($y2) & ':' & ($r2)) $aDist[8] = getDistanceWithBorder($x1 & ':' & $y1 & ':' & $r1, ($x2 + $iMapWidth) & ':' & ($y2 + $iMapHeight) & ':' & ($r2)) Return Min9($aDist[0], $aDist[1], $aDist[2], $aDist[3], $aDist[4], $aDist[5], $aDist[6], $aDist[7], $aDist[8]) EndFunc Func getDistanceWithBorder($sStart, $sTarget) Local $aTmp1 = StringSplit($sStart, ':', 2), $aTmp2 = StringSplit($sTarget, ':', 2) Local $x1 = Int($aTmp1[0]), $y1 = Int($aTmp1[1]), $r1 = Int($aTmp1[2]) Local $x2 = Int($aTmp2[0]), $y2 = Int($aTmp2[1]), $r2 = Int($aTmp2[2]) Local $ax = ($x1 - 1) * $iMapRoot + Mod($r1 - 1, $iMapRoot) Local $ay = ($y1 - 1) * $iMapRoot + Int(($r1 - 1)/$iMapRoot) Local $bx = ($x2 - 1) * $iMapRoot + Mod($r2 - 1, $iMapRoot) Local $by = ($y2 - 1) * $iMapRoot + Int(($r2 - 1)/$iMapRoot) Local $iDist = Min2(Abs($ax - $bx), Abs($ay - $by)) $ax += $ax > $bx ? -$iDist : $iDist $ay += $ay > $by ? -$iDist : $iDist Return $iDist + Abs($ax - $bx) + Abs($ay - $by) EndFunc Func Min($a, $b) Return $a < $b ? $a : $b EndFunc ;==>Min Func Min2($a, $b) Return $a < $b ? $a : $b EndFunc Func Min3($a, $b, $c) Return $a < $b ? $a < $c ? $a : $c : $b < $c ? $b : $c EndFunc Func Min9($1, $2, $3, $4, $5, $6, $7, $8, $9) Return Min3(Min3($1, $2, $3), Min3($4, $5, $6), Min3($7, $8, $9)) EndFunc Func Max($a, $b) Return $a > $b ? $a : $b EndFunc A section of the coordinate system to understand it: ;~ --------------------------- + ------------------------ + ------------------------ ;~ 60:60:1 | 60:60:2 | 60:60:3 | 1:60:1 | 1:60:2 | 1:60:3 | 2:60:1 | 2:60:2 | 2:60:3 ;~ --------------------------- | ------------------------ | ------------------------ ;~ 60:60:4 | 60:60:5 | 60:60:6 | 1:60:4 | 1:60:5 | 1:60:6 | 2:60:4 | 2:60:5 | 2:60:6 ;~ --------------------------- | ------------------------ | ------------------------ ;~ 60:60:7 | 60:60:8 | 60:60:9 | 1:60:7 | 1:60:8 | 1:60:9 | 2:60:7 | 2:60:8 | 2:60:9 ;~ --------------------------- + ------------------------ + ------------------------ ;~ 60:1:1 | 60:1:2 | 60:1:3 | 1:1:1 | 1:1:2 | 1:1:3 | 2:1:1 | 2:1:2 | 2:1:3 ;~ --------------------------- | ------------------------ | ------------------------ ;~ 60:1:4 | 60:1:5 | 60:1:6 | 1:1:4 | 1:1:5 | 1:1:6 | 2:1:4 | 2:1:5 | 2:1:6 ;~ --------------------------- | ------------------------ | ------------------------ ;~ 60:1:7 | 60:1:8 | 60:1:9 | 1:1:7 | 1:1:8 | 1:1:9 | 2:1:7 | 2:1:8 | 2:1:9 ;~ --------------------------- + ------------------------ + ------------------------ ;~ 60:2:1 | 60:2:2 | 60:2:3 | 1:2:1 | 1:2:2 | 1:2:3 | 2:2:1 | 2:2:2 | 2:2:3 ;~ --------------------------- | ------------------------ | ------------------------ ;~ 60:2:4 | 60:2:5 | 60:2:6 | 1:2:4 | 1:2:5 | 1:2:6 | 2:2:4 | 2:2:5 | 2:2:6 ;~ --------------------------- | ------------------------ | ------------------------ ;~ 60:2:7 | 60:2:8 | 60:2:9 | 1:2:7 | 1:2:8 | 1:2:9 | 2:2:7 | 2:2:8 | 2:2:9 ;~ --------------------------- + ------------------------ + ------------------------ Maybe this one helps either, to understand it: #include <Array.au3> $aTable = Create(60, 60, 3) ; Zum Anzeigen des ganzen Systems als Array _ArrayDisplay($aTable) Func Create($iTableHeight = 3, $iTableWidth = 3, $iTableElementsRoot = 3) Local $aRet[$iTableHeight * $iTableElementsRoot][$iTableWidth * $iTableElementsRoot] For $y = 0 To $iTableHeight - 1 Step 1 For $x = 0 To $iTableWidth - 1 Step 1 For $i = 1 To $iTableElementsRoot ^ 2 Step 1 $aRet[$y * $iTableElementsRoot + Int(($i-1)/$iTableElementsRoot)][$x * $iTableElementsRoot + Mod($i - 1, $iTableElementsRoot)] = $i Next Next Next Return $aRet EndFunc
  4. Hmmm, there is no "check" if you write it like that?! The "checking part" is always "0". After I tried it anyway, it no longer worked.
  5. Ok, I did add the calculation of the tasks target time and a function to show me the queue. Iam pretty happy with that state... Do you guys have ideas to improve it? Should I use another data type instead of an array? Do you see any weaknesses, apart from the fact that I deliberately do without multithreading? #include <Array.au3> #include <Date.au3> ENUM $TASK_INTERVAL, $TASK_FUNCTION, $TASK_PARAMETER, $TASK_REPEAT, $TASK_HTIMER, $TASK_DATE Global $taskQueue[0][6] AddTask(3, "Task1") AddTask(5, "Task2", "", True) AddTask(7, "Task_") DeleteTask("Task_") AddTask(12, "Task3") AddTask(20, "_Exit") AddTask(12, "TaskX", "param") OutputTaskQueue() While Sleep(250) CheckTasks() WEnd Func CheckTasks() For $i = UBound($taskQueue) -1 To 0 Step -1 If TimerDiff($taskQueue[$i][$TASK_HTIMER]) > $taskQueue[$i][$TASK_INTERVAL] Then ConsoleWrite("call " & $taskQueue[$i][$TASK_FUNCTION] & @CRLF) ConsoleWrite(" time:" & Round(TimerDiff($taskQueue[$i][$TASK_HTIMER]) / 1000, 3) & " seconds") Call($taskQueue[$i][$TASK_FUNCTION], $taskQueue[$i][$TASK_PARAMETER] ? $taskQueue[$i][$TASK_PARAMETER] : "") If $taskQueue[$i][$TASK_REPEAT] Then $taskQueue[$i][$TASK_HTIMER] = TimerInit() Else _ArrayDelete($taskQueue, $i) EndIf EndIf Next EndFunc Func AddTask($iInterval, $sFunction, $vParameter = False, $bRepeat = False, $hTimer = 0, $sDate = "") ; iInterval in Seconds $hTimer = $hTimer ? $hTimer : TimerInit() $iInterval *= 1000 ; from s to ms $sDate = _DateAdd('s', $iInterval / 1000, _NowCalc()) Local $aArray[1][6] = [[$iInterval, $sFunction, $vParameter, $bRepeat, $hTimer, $sDate]] _ArrayAdd($taskQueue, $aArray) EndFunc Func DeleteTask($sFunction) For $i = UBound($taskQueue) - 1 To 0 Step -1 If StringCompare($sFunction, $taskQueue[$i][$TASK_FUNCTION]) = 0 Then _ArrayDelete($taskQueue, $i) Next EndFunc Func _Exit() ConsoleWrite("Getting closed!" & @CRLF) Exit EndFunc ;==>_ExitFunction Func Task1() ConsoleWrite(": Task1 completed!" & @CRLF) EndFunc Func Task2() ConsoleWrite(": Task2 completed!" & @CRLF) EndFunc Func Task3() ConsoleWrite(": Task3 completed!" & @CRLF) EndFunc Func TaskX($iParam) ConsoleWrite(": TaskX completed with " & $iParam & "!" & @CRLF) EndFunc Func Task_() ConsoleWrite(": [ERROR] Task_ shouldnt be executed!" & @CRLF) EndFunc Func OutputTaskQueue() ; does not consider repetitive tasks ConsoleWrite("Task Queue:" & @CRLF) For $i = 0 To UBound($taskQueue) - 1 ConsoleWrite($taskQueue[$i][$TASK_DATE] & " | " & $taskQueue[$i][$TASK_FUNCTION] & @CRLF) Next ConsoleWrite(@CRLF) EndFunc *Edit* I added a DeleteTask-Function and an Enumn to make the array handling a little bit easier. *Edit_2* I changed the CheckTask, so its using the AddTask and DeleteTask. So $TASK_DATE gets calculated again for repeatable tasks. Looks a little bit messy now... ^^' #include <Array.au3> #include <Date.au3> ENUM $TASK_INTERVAL, $TASK_FUNCTION, $TASK_PARAMETER, $TASK_REPEAT, $TASK_HTIMER, $TASK_DATE Global $taskQueue[0][6] AddTask(3, "Task1") AddTask(5, "Task2", "", True) AddTask(7, "Task_") DeleteTask("Task_") AddTask(12, "Task3") AddTask(20, "_Exit") AddTask(12, "TaskX", "param") OutputTaskQueue() While Sleep(250) CheckTasks() WEnd Func CheckTasks() For $i = UBound($taskQueue) -1 To 0 Step -1 If TimerDiff($taskQueue[$i][$TASK_HTIMER]) > $taskQueue[$i][$TASK_INTERVAL] Then ConsoleWrite("call " & $taskQueue[$i][$TASK_FUNCTION] & @CRLF) ConsoleWrite(" time:" & Round(TimerDiff($taskQueue[$i][$TASK_HTIMER]) / 1000, 3) & " seconds") Call($taskQueue[$i][$TASK_FUNCTION], $taskQueue[$i][$TASK_PARAMETER] ? $taskQueue[$i][$TASK_PARAMETER] : "") Local $aTempTaskParams[4] = [$taskQueue[$i][$TASK_INTERVAL] / 1000, $taskQueue[$i][$TASK_FUNCTION], $taskQueue[$i][$TASK_PARAMETER], $taskQueue[$i][$TASK_REPEAT]] DeleteTask($i) If $taskQueue[$i][$TASK_REPEAT] Then AddTask($aTempTaskParams[0], $aTempTaskParams[1], $aTempTaskParams[2], $aTempTaskParams[3]) EndIf Next EndFunc Func AddTask($iInterval, $sFunction, $vParameter = False, $bRepeat = False, $hTimer = 0, $sDate = "") ; iInterval in Seconds $hTimer = $hTimer ? $hTimer : TimerInit() $iInterval *= 1000 ; from s to ms $sDate = _DateAdd('s', $iInterval / 1000, _NowCalc()) Local $aArray[1][6] = [[$iInterval, $sFunction, $vParameter, $bRepeat, $hTimer, $sDate]] _ArrayAdd($taskQueue, $aArray) _ArraySort($taskQueue, 0, 0, 0, $TASK_DATE) EndFunc Func DeleteTask($vDeleteTask) If IsInt($vDeleteTask) Then ; delete a special ID _ArrayDelete($taskQueue, $vDeleteTask) Else ; Delete all functions with that name For $i = UBound($taskQueue) - 1 To 0 Step -1 If StringCompare($vDeleteTask, $taskQueue[$i][$TASK_FUNCTION]) = 0 Then _ArrayDelete($taskQueue, $i) Next EndIf EndFunc Func _Exit() ConsoleWrite(": Getting closed!" & @CRLF) Exit EndFunc ;==>_ExitFunction Func Task1() ConsoleWrite(": Task1 completed!" & @CRLF) EndFunc Func Task2() ConsoleWrite(": Task2 completed!" & @CRLF) EndFunc Func Task3() ConsoleWrite(": Task3 completed!" & @CRLF) EndFunc Func TaskX($iParam) ConsoleWrite(": TaskX completed with " & $iParam & "!" & @CRLF) EndFunc Func Task_() ConsoleWrite(": [ERROR] Task_ shouldnt be executed!" & @CRLF) EndFunc Func OutputTaskQueue() ; does not consider repetitive tasks ConsoleWrite("Task Queue:" & @CRLF) For $i = 0 To UBound($taskQueue) - 1 ConsoleWrite($taskQueue[$i][$TASK_DATE] & " | " & $taskQueue[$i][$TASK_FUNCTION] & @CRLF) Next ConsoleWrite(@CRLF) EndFunc *Edit 3* Added the sorting into AddTask
  6. Thanks for your input. I'm a bit nervous about multithreading. I tried it out once and I found it very complicated to no longer clearly know the sequence of the executed functions. Sometimes they use the same data, read and write, and I have the feeling that it doesn't need that. I'm completely happy if a task only happens one after the other and then, for example, a notification/alarm is delayed by a few seconds. @ioa747 Thanks for the examples. I need to add tasks and delete them and Iam wondering what data type is makes the most sense for this. Arrays dont like to get changed its size, so maybe a map!? And I would like to have a sorted "queue" to debug. Maybe its even a good idea to work with dates, instead of timers?! Ill start to fuse your example with mine and then Ill try out a different data type and time format. *edit* Iam here now: #include <Array.au3> ; [0]Timestamp, [1] = Function, [2] = Parameter, [3] = Repeat, [4] = hTimer Global $taskQueue[0][5] AddTask(3000, "Task1") AddTask(5000, "Task2", "", True) AddTask(12000, "Task3") AddTask(20000, "_Exit") AddTask(12000, "TaskX", "param") While Sleep(250) CheckTasks() WEnd Func CheckTasks() For $i = UBound($taskQueue) -1 To 0 Step -1 If $taskQueue[$i][4] = 0 Then $taskQueue[$i][4] = TimerInit() ContinueLoop EndIf If TimerDiff($taskQueue[$i][4]) > $taskQueue[$i][0] Then ConsoleWrite("call " & $taskQueue[$i][1] & @CRLF) ConsoleWrite(" time:" & Round(TimerDiff($taskQueue[$i][4]) / 1000, 3) & " seconds") Call($taskQueue[$i][1], $taskQueue[$i][2] ? $taskQueue[$i][2] : "") If $taskQueue[$i][3] Then $taskQueue[$i][4] = TimerInit() Else _ArrayDelete($taskQueue, $i) EndIf EndIf Next EndFunc Func AddTask($iInterval, $sFunction, $vParameter = False, $bRepeat = False,$hTimer = 0) Local $aArray[1][5] = [[$iInterval, $sFunction, $vParameter, $bRepeat, $hTimer]] _ArrayAdd($taskQueue, $aArray) EndFunc Func _Exit() ConsoleWrite("Getting closed!" & @CRLF) Exit EndFunc ;==>_ExitFunction Func Task1() ConsoleWrite(": Task1 completed!" & @CRLF) EndFunc Func Task2() ConsoleWrite(": Task2 completed!" & @CRLF) EndFunc Func Task3() ConsoleWrite(": Task3 completed!" & @CRLF) EndFunc Func TaskX($iParam) ConsoleWrite(": TaskX completed with " & $iParam & "!" & @CRLF) EndFunc
  7. Maybe Iam too tired and my description wasnt good, sorry...^^ I would like to know, if something like this (maybe not with an array, but its quick'n'dirty to show, what I try to achieve): #include <Array.au3> Global $taskQueue[0][2] ; [0] = Timestamp, [1] = Function AddTask(TimerInit() + 2500, "MyRepeatableFunction") AddTask(TimerInit() + 15000, "MyFunction") AddTask(TimerInit() + 20000, "MyFunction") AddTask(TimerInit() + 20000, "_ExitFunction") While Sleep(250) CheckTasks() WEnd Func MyFunction() ConsoleWrite("Task completed!" & @CRLF) EndFunc Func _ExitFunction() ConsoleWrite("Getting closed!" & @CRLF) Exit EndFunc Func MyRepeatableFunction() ConsoleWrite("Repeatable task completed!" & @CRLF) AddTask(TimerInit() + 2500, "MyRepeatableFunction") ; add the same function again EndFunc Func AddTask($interval, $function) Local $aTask[1][2] = [[$interval, $function]] _ArrayAdd($taskQueue, $aTask) _ArraySort($taskQueue) EndFunc Func CheckTasks() Local $currentTime = TimerInit() If UBound($taskQueue) > 0 Then If $currentTime >= $taskQueue[0][0] Then Call($taskQueue[0][1]) ; call the function _ArrayDelete($taskQueue, 0) ; delete the task EndIf EndIf EndFunc Its not working on the repeatable task and Iam not sure, if this direction is a "good" one... Like this I would have a global list with all the tasks and next timings. The code is now without GUI, because it is basically the same and so it is easier to show what I mean by "scheduled task queue".
  8. Hey, what is the best way to do a scheduled task queue? Iam usally using OnEvent in my GUI and if I have to time tasks, I use AdlibRegister and AdlibUnRegister. Thats working pretty well: one task doesnt disturb the other ones. But I cant see the status of the Adlibs and Im always happy to learn about better ways to do something I found the "_AdlibEnhance.au3", which should improve the possibilites, but its still Adlib. A little bit more specific on the use case: I don't believe that this is a special use case and think that there must be a UDF for this that I just haven't found yet or that there are at least better solutions than "Adlib". Maybe some "sorted list" (by timestamps) and checking the top entry timestamp every few ms in the main loop? And If I add a new entry, I sort the list again? And it just checks, if the tasks timestamp is in the past?! And to add entries, for example "check the weather every 5 min", I just calculate the target time stamp and I use the "check weather function" to add another entry, after the check is done. Not sure, how I call the functions from something like this. Maybe with a string of the function in the list and then using "Eval()"?!
  9. Thank you To (2) (FAQ #3) => Its a little "problematic". Your solution brings me to I found some input about that. The problem seems to be, that I already use my Chrome profile and the new instance with the same profile is a problem for Chrome. So I have to end existing Chrome instances, before using the code or I have to use a different profile for the Web Driver, but the new profile wouldnt be synced. Both ways are not "optimal"^^. As far as I read some of your answers, I cant join an existing session of Chrome, right? (Just, if the session was started with Chrome Driver and the same parameters) Do you have any idea? *edit* Even with another profile I get the error and no valid session id, because he cant move the cache. Hes starting the instance with the new profile, but he still tries to use the already used cache, hmmm... --- https://stackoverflow.com/questions/59987080/invalidargumentexception-message-invalid-argument-user-data-directory-is-alre https://forum.katalon.com/t/user-data-directory-is-already-in-use/40266/2 https://stackoverflow.com/questions/50635087/how-to-open-a-chrome-profile-through-user-data-dir-argument-of-selenium
  10. Hey, a really nice UDF! I have 2 questions: How can I size the window? I found "_WD_Window() with "rect", but I couldnt find any informations about the syntax of the options... "maximize" and "fullscreen" are working, but I would like to set a specific size. I tried a lot of things, but Stackoverflow and Google just answer it for Python and other toolings. For example "--height=1440" isnt working. And can I set that somehow directly with the session start? Maybe with the "$sDesiredCapabilities"? Is it possible to force the Chrome Driver to use your "normal Chrome"? Like all extensions, cookies and my logged in Google account... After the session he really forgets everything I just want to start some pages, do stuff and "take over by myself". And its really akward to miss extensions, cookies and the logged in Google account ^^ Thank you!
  11. Thank you, but that wont work for me I need it like a queue, but with the Adlib force (dont wait for other stuff, besides other Adlib-started things ^^). I have one function, that is processing the main work for me and it has three different "triggers" (one param, that can come in 3 different expressions, lets say "1, 2 and 3): If its "1", the data from source "1" gets used, "2" triggers the usage of the data from "2" and "3" calling the function to use a third data source. If the function for example processed the data from source "1" by calling the "$iParam" with "1", it calculates the next Adlib-Time overwrite the time for the next time, the function has to use the "1". I didnt find other solutions for a "queue" like that. Currently I'm thinking about using the "Execute()" function and continue using the "Adlib Helper Functions", but then create them dynamically. This should be the best way to tell a function to run in x seconds with the parameter y, right? *edit* Oh, and I fund "_Timer_SetTimer()"... That looks promising, too... Thats the function this UDF is based on, ahhhh... I will take a deeper look into this *edit2* Not that simple... Would be nice to find the UDF, to re-use it. Link is dead.
  12. Hey, the UDF is still working, so I hope to find some help or a "newer" UDF :) I want to register one function with different Paramters. Like this, but this isnt working: #include "_AdlibEnhance.au3" _Adlib_Register("_MyAdlib", "1", 1000) _Adlib_Register("_MyAdlib", "2", 2000) _Adlib_Register("_Exit", "", 5000) While 1 GUIGetMsg() WEnd Func _MyAdlib($sText) ConsoleWrite($sText & @CRLF) EndFunc ;==>MyAdlib Func _Exit() Sleep(2000) Exit EndFunc ;==>_Exit Right now my code isnt very flexible, I use "Helper"-functions like this: AdlibRegister("AdlibHelperPega" & $iID) Func AdlibHelper1() _MyAdlib(1) EndFunc Func AdlibHelper2() _MyAdlib(2) EndFunc
  13. Sad, that this UDF is outdated. Looks amazing
  14. Hey, thank you. Still trying to understand this cookie handling. What does a browser with the "Set-Cookie:"-part, to "know", what he needs to send as "Cookie:" in the next request?
×
×
  • Create New...