1. Dashboard
  2. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team
    4. Mitgliedersuche
  3. Forenregeln
  4. Forum
    1. Unerledigte Themen
  • Anmelden
  • Registrieren
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Forum
  • Erweiterte Suche
  1. AutoIt.de - Das deutschsprachige Forum.
  2. Mitglieder
  3. Kanashius

Beiträge von Kanashius

  • AutoIt-Hackathon #3 "alte Zeiten"

    • Kanashius
    • 12. Mai 2025 um 17:16
    Zitat von Moombas

    Die tatsächliche Anforderung wäre hier also: "Input date in the format "DD/MM/YYYY HH:MM:SS" "

    Die [] klammern werden tatsächlich normalerweise so angegeben um zu signaliesieren, dass etwas optional ist. Richtig wäre also eher: DD/MM/YYYY[ HH[:MM[:SS]]], da die Zeit nochmal mehrere optionale Felder hat.

    Aber ja, ich bin auch darüber gestolpert... Das erste mal mit DD/MM/YYYY statt YYYY/MM/DD und dann mit dem optionalen,... Irgendwann hab ich mir gedacht, ich ignorier das vorgegebene Muster und ersetze einfach alle Zahlen, dann ist definitiv alles abgedeckt :D

  • AutoIt-Hackathon #3 "alte Zeiten"

    • Kanashius
    • 12. Mai 2025 um 00:45

    Etwas später, aber besser spät als nie ;)

    AutoIt
    ; ================================= entferne alle Leer- und Kommentarzeilen und poste diesen Code-Block im Thread ==================================
    Func _IntegerToRoman($sInteger)
    	Local Static $arPattern=["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]
    	Local Static $arNumbers=[["I", "V"], ["X", "L"], ["C", "D"], ["M", ""], ["", ""]]
    	Local $arData = StringSplit($sInteger, "", 3)
    	Local $sResult = ""
    	For $i=0 To UBound($arData)-1 Step 1
    		Local $sSym1 = $arNumbers[UBound($arData)-$i-1][0]
    		Local $sSym2 = $arNumbers[UBound($arData)-$i-1][1]
    		Local $sSym3 = $arNumbers[UBound($arData)-$i][0]
    		$sResult &= StringReplace(StringReplace(StringReplace($arPattern[$arData[$i]], "X", $sSym3), "V", $sSym2), "I", $sSym1)
    	Next
    	Return $sResult
    EndFunc   ;==>_IntegerToRoman
    Func _RomanToInteger($sRoman)
    	Local $arData = StringSplit($sRoman, "", 3), $iResult = 0, $iBefore = 0
    	For $i=0 To UBound($arData)-1 Step 1
    		Local $iAdd = 0
    		Switch $arData[$i]
    			Case "M"
    				$iAdd+=1000
    			Case "D"
    				$iAdd+=500
    			Case "C"
    				$iAdd+=100
    			Case "L"
    				$iAdd+=50
    			Case "X"
    				$iAdd+=10
    			Case "V"
    				$iAdd+=5
    			Case "I"
    				$iAdd+=1
    		EndSwitch
    		If $iBefore<$iAdd Then
    			$iResult-=$iBefore*2
    		EndIf
    		$iResult+=$iAdd
    		$iBefore = $iAdd
    	Next
    	Return $iResult
    EndFunc   ;==>_RomanToInteger
    Func _DateToRoman($sDate) ;Input date in the format "YYYY/MM/DD[ HH:MM:SS]", Output in same date-format with roman sign
    	Local $arDate = StringRegExp($sDate, "\d+", 3)
    	$sDate = StringRegExpReplace($sDate, "\d+", "$")
    	For $i=0 To UBound($arDate)-1
    		$sDate = StringReplace($sDate, "$", _IntegerToRoman($arDate[$i]), 1)
    	Next
    	Return $sDate
    EndFunc   ;==>_DateToRoman
    ; ================================= entferne alle Leer- und Kommentarzeilen und poste diesen Code-Block im Thread ==================================
    Alles anzeigen
  • Datenbank : Teil 1 erstellen einer DB

    • Kanashius
    • 8. Mai 2025 um 16:37

    Hi Alina,

    Ich hab das ganze diesmal auch in eine SQLite Datenbank geschrieben.
    Nur den Tagesverbrauch hab ich weggelassen, da ich den noch nicht wirklich verstanden habe (ist das ein Durchschnitt nach Monatstag? weil es ist kein Datum dabei um einen bestimmten Monat anzugeben).

    Achte auch darauf, dass ich nicht nur die Tabellen angelegt habe, sondern auch einige Views als Beispiel zur Datenabfrage.
    Die Views können wie Tabellen auch in SQL-Abfragen verwendet werden.

    Was das Datum und die Beträge angeht: Lass sie als YYYY-MM-DD und 10.0 in der Datenbank. Das sind die Internationalen Standards, die SQLite automatisch erkennt und verwendet. Ansonsten kann bei den SQLite Operationen (Wie Summe (SUM), Durchschnitt (AVG), Runden (ROUND),...) und den Vergleichen für die Abfragen einiges schief gehen.

    Mach erst alles in SQLite und am Ende baust du dir die Deutsche Variante daraus (In SQL oder AutoIt, je nachdem, wie es besser passt).

    Ein Beispiel für SQLite: SELECT ID, Account, AccountName, Type, TypeName, strftime('%d.%m.%Y %H:%M:%S', Time) as TimeDE, REPLACE(CAST(Change as text), '.', ',') as ChangeDE FROM CombinedBalanceForCalculations

    Edit: Hab die Datenbank noch mit mehr Beispieldaten befüllt (2024/2025) und die Saldo Views überarbeitet, um nicht nur die Veränderung, sondern auch den aktuellen Stand mit auszugeben (z.B. SaldoBefore, SaldoAfter für jeden Monat)

    Dateien

    db_ahl_kanashius.zip 8,09 kB – 11 Downloads
  • array(s) nach daten durchsuchen und zuordnen und damit dann ein neues array anlegen

    • Kanashius
    • 3. Mai 2025 um 15:29


    Hier mal, wie ich die Fragestellungen angehen würde:
    Zu 1.:
    - Liste mit allen Strecken anlegen (mit IDs e.g. StreckenID (nummer zur identifizierung für PC) und Namen (identifizierung für Menschen; muss nicht eindeutig sein))
    - Liste mit Weichen/"Kreuzungen" erstellen (mit eigener WeichenID) und einer Liste mit StreckenIDs, wo man von dort hin kann, keine Ahnung, ob Weichen auch namen brauchen
    - ggf. die Liste mit StreckenIDs in eingehende/ausgehende Strecken unterteilen. Weiche X (WeichenID 1) geht z.b. von Strecke A (StreckenID 1) nach Strecke B (StreckenID 2) oder C (StreckenID 3)
    - Man könnte das ganze dann sogar erweitern mit einer Liste an koordinaten für jede Strecke (Als Pfad, der die Strecke definiert) und das ganze visuell als Grafik abbilden
    - _GDIPlus_GraphicsDrawClosedCurve

    - Die Daten würde ich nicht als INI, sondern als JSON anlegen:
    - https://github.com/Sylvan86/autoit-json-udf dort die JSON.au3 herunterladen
    Das würde dann so aussehen:

    Code
    {
     "Strecken": {
       "1": {
         "name": "A",
         "path": [
           [0, 0],
           [15, 0]
         ]
       },
       "2": {
         "name": "B",
         "path": [
           [5, 5],
           [10, 0]
         ]
       },
       "3": {
         "name": "C",
         "path": [
           [5, 5],
           [5, 10]
         ]
       }
     },
     "Weichen":{
       "1": {
         "in": [1],
         "out": [2,3]
       }
     }
    }
    Alles anzeigen


    Wenn du das mit _JSON_Parse einliest, bekommst du direkt eine Map mit allen Daten.
    Ich würde auch darüber nachdenken, das mit SQL (SQLite) zu lösen und in einer Datenbank abzulegen, das würde aber eine Menge der Logik nach SQL verlegen, was vllt. schwerer für dich wäre.

    Zu 2.:
    - da müsste ich mehr wissen um aktiv zu helfen, bzw. Beispiele zu geben

    Zu 3.:
    - Schau dir mal Endliche Automaten (Finite-state machines) an. Da werden States definiert, und von einem State geht man unter bestimmten bedingungen in einen anderen State über.
    Bei jedem State würde man dann für alle Ampeln den aktuellen status (Ampel Farbe) festlegen

    Zu 4/5.:
    - Ok, da hast du ja schon was :)

    Zu 6.:
    - Da würde ich wirklich in Richtung Datenbank mit SQLite schauen, die sind genau für sowas ausgelegt und ein paar einfache Abfragen sollten zu machen sein.

    Zu 7.: Spaß ist die Hauptsache :)

  • Datenbank : Teil 1 erstellen einer DB

    • Kanashius
    • 27. April 2025 um 20:35

    Hi, ich hab die aktuellsten von der SQLite Website heruntergeladen und umbenannt (https://sqlite.org/download.html) :)

    Ich hab sie mal angehängt.

    Dateien

    accountingAlina.zip 5,77 MB – 16 Downloads
  • Datenbank : Teil 1 erstellen einer DB

    • Kanashius
    • 27. April 2025 um 14:20

    argumentum Nichts mehr, der war mal dafür da, dass ich das BEGIN TRANSACTION;, COMMIT; und ggf. ROLLBACK; nicht immer hinzufüge, sondern nur, wenn $bTransaction True ist (was ich dann bei CREATE TABLE,... ausgeschaltet hatte).

    Ist also nur ein überbleibsel aus der Entwicklungszeit ;)

  • Datenbank : Teil 1 erstellen einer DB

    • Kanashius
    • 26. April 2025 um 23:10

    Ich hab mal was gebastelt ;)

    Zuallererst: Alle deine Infos lassen sich recht kurz zusammenfassen: Geld wird einem Konto hinzugefügt oder abgezogen.

    Alles andere sind Infos, die du aus den Daten herausfinden (berechnen) willst.

    Dafür schaut man sich mal an, welche Daten denn wirklich von dir vorgegeben sind, die nicht allgemein gültig sind oder berechnet werden können.
    Das sind einmal die Konten (accounts) sowie die Transaktionen auf den accounts (ein/auszahlungen).
    Also brauchen wir eine Tabelle für die Accounts und eine für die Transaktionen.
    Transaktionen haben als Info: Zeitpunkt, Die Änderung (+-), eine kurze Beschreibung und einen Verwendungszweck.

    Meine Tabellen sehen also so aus:

    Accounts
    id - primary key, wird automatisch erzeugtname - Name des Kontos
    Bookings
    id - primary key, wird automatisch erzeugtaccount - (id aus Accounts)time - zeit als unixepochchange - (Änderung in cent)short_desc - Kurze Beschreibungpurpose - der Verwendungszweck

    Diese werden in SQLite so angelegt:

    Code
    CREATE TABLE IF NOT EXISTS Bookings(
    	id INTEGER PRIMARY KEY,
    	account INTEGER NOT NULL,
    	time INTEGER DEFAULT (unixepoch()),
    	change INTEGER NOT NULL,
    	short_desc TEXT DEFAULT NULL,
    	purpose TEXT DEFAULT NULL,
    	FOREIGN KEY (account) REFERENCES Accounts (id) ON DELETE CASCADE ON UPDATE NO ACTION
    );
    
    CREATE TABLE IF NOT EXISTS Accounts(
    	id INTEGER PRIMARY KEY,
    	name TEXT NOT NULL
    );
    Alles anzeigen

    Deine Daten können dann mit folgendem hinzugefügt werden:

    Code
    BEGIN TRANSACTION;
    INSERT INTO Bookings (account, time, change, short_desc) VALUES (1, unixepoch("2025-04-25 12:34:56"), 120000, "Einnahmen Lohn1");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, 25000, "Einnahmen Lohn2");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, 15000, "Einnahmen WGP");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, 6000, "Einnahmen LMP VM");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, 4000, "Einnahmen Extra");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, -50000, "Ausgaben Miete");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, -10000, "Ausgaben Strom");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, -1005, "Ausgaben Bank");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, -2000, "Ausgaben RuBe");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, -30000, "Ausgaben LMP");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, -10000, "Ausgaben DuS");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, -15000, "Ausgaben frei1");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, 0, "Ausgaben frei2");
    INSERT INTO Bookings (account, change, short_desc) VALUES (1, 0, "Ausgaben Extra");
    COMMIT;
    
    BEGIN TRANSACTION;
    INSERT INTO Bookings (account, change, short_desc) VALUES (2, 10000, "Eingang Sparbuch");
    INSERT INTO Bookings (account, change, short_desc, purpose) VALUES (2, -7500, "Ausgang Sparbuch", "X, Y, Z");
    COMMIT;
    
    BEGIN TRANSACTION;
    INSERT INTO Accounts (name) VALUES ("Haushaltsbuch"), ("Sparbuch");
    COMMIT;
    Alles anzeigen

    Alles andere wird mit SQL ausgerechnet.
    Für den Startwert, den du angibst kannst du einfach eine weitere Transaktion in Bookings hinzufügen, die den StartWert auf das Konto überweist, e.g. : INSERT INTO Bookings (account, time, change, short_desc) VALUES (1, unixepoch("2000-01-01 00:00:00"), 5000000, "Initiale 50000");


    Und damit du ein Beispiel hast, hab ich mal alle Daten aus deinem Post, die irgendwie errechnet werden können als Ausgabe vorbereitet, du kannst einfach die passenden Zeilen aus/einkommentieren und dir die Abfragen anzeigen lassen.
    Dabei sind zwei Zeilen (41, 46), in denen Daten zum Testen im Zeitraum 2024.01.01 bis 2025.12.28 generiert werden. Besonders das Löschen der alten Tabellen nimmt etwas Zeit ein, also nach dem ersten ausführen am besten die beiden Zeilen auskommentieren.
    _SQLite_ExecCatchErr($hDB, $sSQLReset, False, True)
    _fillWithExampleData($hDB)
    Die SQL-Abfragen sind sehr schnell, wenn das ausführen also mehr als 1 bis 2 Sekunden dauert liegt es daran.

    AutoIt
    #include <SQLite.au3>
    
    Global $sDataFolder = "Data\", $sSQLiteDLL = $sDataFolder&"sqlite3_"&(@AutoItX64?"64":"86")&".dll", $sDatabase = $sDataFolder&"database.sqlite"
    Global $sSQLCreateTableBooking = "" & _
    	"CREATE TABLE IF NOT EXISTS Bookings(" & _
    	  "id INTEGER PRIMARY KEY," & _
    	  "account INTEGER NOT NULL," & _
    	  "time INTEGER DEFAULT (unixepoch())," & _
    	  "change INTEGER NOT NULL," & _
    	  "short_desc TEXT DEFAULT NULL," & _
    	  "purpose TEXT DEFAULT NULL," & _
    	  "FOREIGN KEY (account) REFERENCES Accounts (id) ON DELETE CASCADE ON UPDATE NO ACTION" & _
    	");"
    Global $sSQLCreateTableAccounts = "" & _
    	"CREATE TABLE IF NOT EXISTS Accounts(" & _
    	  "id INTEGER PRIMARY KEY," & _
    	  "name TEXT NOT NULL" & _
    	");"
    Global $sSQLReset = "DROP TABLE IF EXISTS Bookings; DROP TABLE IF EXISTS Accounts;"
    Global $sSQLAllData = "SELECT " & _
    							"b.account, " & _
    							"a.name, " & _
    							"b.time, " & _
    							"datetime(b.time, 'unixepoch') as stime, " & _
    							"strftime('%Y', datetime(b.time, 'unixepoch')) as year, " & _
    							"strftime('%m', datetime(b.time, 'unixepoch')) as month, " & _
    							"strftime('%d', datetime(b.time, 'unixepoch')) as day, " & _
    							"strftime('%w', datetime(b.time, 'unixepoch')) as weekday, " & _
    							"b.change, " & _
    							"b.short_desc, " & _
    							"b.purpose " & _
    						"FROM Bookings b JOIN Accounts a ON b.account=a.id"
    
    _SQLite_Startup($sSQLiteDLL)
    If @error Then MsgBox(16, "Error", 'SQLite could not be loaded. Check, if the file "'&$sSQLiteDLL&'" exists.')
    
    Global $hDB = _SQLite_Open($sDatabase)
    
    ; For Debugging to remove old data
    _SQLite_ExecCatchErr($hDB, $sSQLReset, False, True)
    
    _SQLite_ExecCatchErr($hDB, $sSQLCreateTableBooking, False, True)
    _SQLite_ExecCatchErr($hDB, $sSQLCreateTableAccounts, False, True)
    
    _fillWithExampleData($hDB)
    
    Local $arColumns, $arData
    
    ; Output Table Accounts
    $arData = _SQLite_GetAllCatchErr($hDB, "SELECT * From Accounts", $arColumns)
    _printData($arData, $arColumns, "Table Accounts")
    
    ; Output Table Bookings
    $arData = _SQLite_GetAllCatchErr($hDB, "SELECT * From Bookings", $arColumns)
    _printData($arData, $arColumns, "Table Bookings")
    
    ; Output everything with extra data
    ; $arData = _SQLite_GetAllCatchErr($hDB, $sSQLAllData, $arColumns)
    ; _printData($arData, $arColumns, "All data with extra infos for further processing")
    
    
    ; output change by month
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, month, cast(SUM(change) as float)/100 as change FROM ("&$sSQLAllData&") GROUP BY name, month, year ORDER BY name, year, month", $arColumns)
    ; _printData($arData, $arColumns, "Change by Month-Year")
    
    ; output change by year
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, cast(SUM(change) as float)/100 as change FROM ("&$sSQLAllData&") GROUP BY name, year ORDER BY name, year", $arColumns)
    ; _printData($arData, $arColumns, "Change by Year")
    
    ; output change by half year
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, month/6+1 as halfyear, cast(SUM(change) as float)/100 as change FROM ("&$sSQLAllData&") GROUP BY name, year, (month-1)/6 ORDER BY name, year, halfyear", $arColumns)
    ; _printData($arData, $arColumns, "Change by Half Year")
    
    ; output change by quarter
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, month/3+1 as quarter, cast(SUM(change) as float)/100 as change FROM ("&$sSQLAllData&") GROUP BY name, year, (month-1)/3 ORDER BY name, year, quarter", $arColumns)
    ; _printData($arData, $arColumns, "Change by Quarter")
    
    ; output change by third
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, month/4+1 as third, cast(SUM(change) as float)/100 as change FROM ("&$sSQLAllData&") GROUP BY name, year, (month-1)/4 ORDER BY name, year, third", $arColumns)
    ; _printData($arData, $arColumns, "Change by Year/3")
    
    ; output change by day
    Global $sSQLChangeByDay = "SELECT name, year, month, day, cast(SUM(change) as float)/100 as change FROM ("&$sSQLAllData&") GROUP BY name, year, month, day ORDER BY name, year, month, day"
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, month, day, cast(SUM(change) as float)/100 as change FROM ("&$sSQLAllData&") GROUP BY name, year, month, day ORDER BY name, year, month, day", $arColumns)
    ; _printData($arData, $arColumns, "Change by Day")
    
    ; output spending avarage by day
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, AVG(change) as average FROM ("&$sSQLChangeByDay&") GROUP BY name, year ORDER BY name, year", $arColumns)
    ; _printData($arData, $arColumns, "Average change by day")
    
    ; output spending avarage by week
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, AVG(change)*7 as average FROM ("&$sSQLChangeByDay&") GROUP BY name, year ORDER BY name, year", $arColumns)
    ; _printData($arData, $arColumns, "Average change by week")
    
    ; output spending avarage by weekday
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, weekday, cast(AVG(change) as float)/100 as average FROM ("&$sSQLAllData&") GROUP BY name, year, weekday ORDER BY name, year, weekday", $arColumns)
    ; _printData($arData, $arColumns, "Average change by day")
    
    ; output saldo
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT a.name, cast(SUM(b.change) as float)/100 as saldo FROM Bookings b JOIN Accounts a ON b.account=a.id GROUP BY a.name", $arColumns)
    ; _printData($arData, $arColumns, "Saldo")
    
    ; output saldo until specific datetime
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT a.name, cast(SUM(b.change) as float)/100 as saldo FROM Bookings b JOIN Accounts a ON b.account=a.id WHERE b.time<unixepoch('2025-01-01 00:00:00') GROUP BY a.name", $arColumns)
    ; _printData($arData, $arColumns, "Saldo at 2025-01-01 00-00-00")
    
    ; output change by quarter for year 2025
    ; $arData = _SQLite_GetAllCatchErr($hDB, "SELECT name, year, month/3+1 as quarter, cast(SUM(change) as float)/100 as change FROM ("&$sSQLAllData&") WHERE year='2025' GROUP BY name, year, (month-1)/3 ORDER BY name, year, quarter", $arColumns)
    ; _printData($arData, $arColumns, "Change by Quarter (2025)")
    
    Func _exit()
    	_SQLite_Close($hDB)
    	_SQLite_Shutdown()
    	Exit
    EndFunc
    
    Func _SQLite_ExecCatchErr($hDB, $sSql, $bTransaction = True, $bFatal = False)
    	_SQLite_Exec($hDB, 'BEGIN TRANSACTION;'&$sSql&'COMMIT;')
    	If @error Then
    		_SQLite_Exec($hDB, "ROLLBACK;")
    		MsgBox(16, "SQLite Error", "Error Code: " & _SQLite_ErrCode() & @CRLF & "Error Message: " & _SQLite_ErrMsg() & "Executing """&$sSql&"""")
    		If $bFatal Then _exit()
    	EndIf
    EndFunc
    
    Func _SQLite_GetDataCatchErr($hDB, $sSql)
    	Local $arColumns
    	Return _SQLite_GetAllCatchErr($hDB, $sSql, $arColumns)
    EndFunc
    
    Func _SQLite_GetAllCatchErr($hDB, $sSql, ByRef $arColumns)
    	Local $arResult, $iRows
    	_SQLite_GetTableData2D($hDB, $sSql, $arResult, $iRows, $arColumns)
    	If @error Then
    		MsgBox(16, "SQLite Error", "Error Code: " & _SQLite_ErrCode() & @CRLF & "Error Message: " & _SQLite_ErrMsg() & "Executing """&$sSql&"""")
    		Local $arResult[0][0]
    		Return SetError(1, 0, $arResult)
    	EndIf
    	Return $arResult
    EndFunc
    
    Func _printData(ByRef $arData, ByRef $arColumns, $sTitle = Default)
    	If Not IsArray($arData) Or Not IsArray($arColumns) Then Return -1
    	If UBound($arData,0)<>2 Then Return -1
    	Local $arColWidth[UBound($arData, 2)]
    	For $i=0 To UBound($arColumns)-1 Step 1
    		If StringLen($arColumns[$i])>$arColWidth[$i] Then $arColWidth[$i] = StringLen($arColumns[$i])
    	Next
    	For $j=0 To UBound($arData, 2)-1 Step 1
    		For $i=0 To UBound($arData, 1)-1 Step 1
    			Local $arMatch = StringRegExp($arData[$i][$j], "(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})", 1)
    			If Not @error Then
    				$arData[$i][$j] = $arMatch[0]&"-"&$arMatch[1]&"-"&$arMatch[2]&" "&$arMatch[3]&"-"&$arMatch[4]&"-"&$arMatch[5]
    			EndIf
    			If StringLen($arData[$i][$j])>$arColWidth[$j] Then $arColWidth[$j] = StringLen($arData[$i][$j])
    		Next
    	Next
    	Local $arSeps[UBound($arColWidth)], $iMaxLength = 0
    	For $i=0 To UBound($arColWidth)-1 Step 1
    		$iMaxLength+=$arColWidth[$i]+3
    	Next
    	Local $iAdd = 0
    	If $iMaxLength<StringLen($sTitle) Then $iAdd = Int((StringLen($sTitle)-$iMaxLength+4)/UBound($arColWidth))+(Mod((StringLen($sTitle)-$iMaxLength)+4, UBound($arColWidth))>0?1:0)
    	For $i=0 To UBound($arColWidth)-1 Step 1
    		$arColWidth[$i] += $iAdd
    	Next
    	For $i=0 To UBound($arColWidth)-1 Step 1
    		For $j=0 To $arColWidth[$i]+1 Step 1
    			$arSeps[$i] &= "-"
    		Next
    	Next
    	If $sTitle<>Default Then
    		ConsoleWrite("+")
    		For $i=0 To UBound($arSeps)-1 Step 1
    			ConsoleWrite($arSeps[$i])
    			If $i<UBound($arSeps)-1 Then ConsoleWrite("-")
    		Next
    		ConsoleWrite("+"&@crlf)
    		Local $iTitleSpace = Int(($iMaxLength-3-StringLen($sTitle))/2)
    		If $iTitleSpace<0 Then $iTitleSpace=0
    		Local $iExtra = 0
    		If Mod(($iMaxLength-3-StringLen($sTitle))/2, 2)<>0 Then $iExtra = 1
    		ConsoleWrite(StringFormat("| %"&$iTitleSpace&"s%s%"&$iTitleSpace+$iExtra&"s |", "", $sTitle, "")&@crlf)
    	EndIf
    	For $i=0 To UBound($arSeps)-1 Step 1
    		ConsoleWrite("+"&$arSeps[$i])
    	Next
    	ConsoleWrite("+"&@crlf)
    	For $i=0 To UBound($arColumns)-1 Step 1
    		ConsoleWrite(StringFormat("| %-"&$arColWidth[$i]&"s ", StringUpper($arColumns[$i])))
    	Next
    	ConsoleWrite("| "&@crlf)
    	ConsoleWrite("+")
    	For $i=0 To UBound($arSeps)-1 Step 1
    		ConsoleWrite($arSeps[$i])
    		If $i<UBound($arSeps)-1 Then ConsoleWrite("-")
    	Next
    	ConsoleWrite("+"&@crlf)
    	For $i=0 To UBound($arData, 1)-1 Step 1
    		For $j=0 To UBound($arData, 2)-1 Step 1
    			ConsoleWrite(StringFormat("| %-"&$arColWidth[$j]&"s ", $arData[$i][$j]))
    		Next
    		ConsoleWrite("| "&@crlf)
    	Next
    	For $i=0 To UBound($arSeps)-1 Step 1
    		ConsoleWrite("+"&$arSeps[$i])
    	Next
    	ConsoleWrite("+"&@crlf)
    EndFunc
    
    Func _fillWithExampleData($hDB)
    	_SQLite_ExecCatchErr($hDB, 'INSERT INTO Accounts (name) VALUES ("Haushaltsbuch"), ("Sparbuch");')
    	#cs
    	_SQLite_ExecCatchErr($hDB, '' & _
    			'INSERT INTO Bookings (account, time, change, short_desc) VALUES (1, unixepoch("2025-04-25 12:34:56"), 120000, "Einnahmen Lohn1");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, 25000, "Einnahmen Lohn2");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, 15000, "Einnahmen WGP");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, 6000, "Einnahmen LMP VM");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, 4000, "Einnahmen Extra");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, -50000, "Ausgaben Miete");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, -10000, "Ausgaben Strom");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, -1005, "Ausgaben Bank");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, -2000, "Ausgaben RuBe");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, -30000, "Ausgaben LMP");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, -10000, "Ausgaben DuS");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, -15000, "Ausgaben frei1");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, 0, "Ausgaben frei2");' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (1, 0, "Ausgaben Extra");' & _
    		'')
    	_SQLite_ExecCatchErr($hDB, '' & _
    			'INSERT INTO Bookings (account, change, short_desc) VALUES (2, 10000, "Eingang Sparbuch");' & _
    			'INSERT INTO Bookings (account, change, short_desc, purpose) VALUES (2, -7500, "Ausgang Sparbuch", "X, Y, Z");' & _
    		'')
    	#ce
    	; generate some example data for 2024+2025 (complete years)
    	Local $arData = [ _
    		[1, 120000, "Einnahmn Lohn1", ""], _
    		[1, 25000, "Einnahmen Lohn2", ""], _
    		[1, 15000, "Einnahmen WGP", ""], _
    		[1, 6000, "Einnahmen LMP VM", ""], _
    		[1, 4000, "Einnahmen Extra", ""], _
    		[1, -50000, "Ausgaben Miete", ""], _
    		[1, -10000, "Ausgaben Strom", ""], _
    		[1, -1005, "Ausgaben Bank", ""], _
    		[1, -2000, "Ausgaben RuBe", ""], _
    		[1, -30000, "Ausgaben LMP", ""], _
    		[1, -10000, "Ausgaben DuS", ""], _
    		[1, -15000, "Ausgaben frei1", ""], _
    		[1, 0, "Ausgaben frei2", ""], _
    		[1, 0, "Ausgaben Extra", ""], _
    		[2, 10000, "Eingang Sparbuch", ""], _
    		[2, -7500, "Ausgang Sparbuch", "X, Y, Z"] _
    	]
    	For $iYear=2024 To 2025 Step 1
    		For $iMonth=1 To 12 Step 1
    			Local $sSql = ""
    			For $i=0 To UBound($arData)-1 Step 1
    				Local $iDay = Random(1, 28, 1)
    				Local $sDate = StringFormat("%04d-%02d-%02d %02d:%02d:%02d", $iYear, $iMonth, $iDay, 12, 30, 00)
    				Local $iMultiplier = Random(0.6, 1)
    				If $arData[$i][3]="" Then
    					$sSql &= StringFormat('INSERT INTO Bookings (account, time, change, short_desc) VALUES (%d, unixepoch("%s"), %d, "%s");', $arData[$i][0], $sDate, $arData[$i][1]*$iMultiplier, $arData[$i][2])
    				Else
    					$sSql &= StringFormat('INSERT INTO Bookings (account, time, change, short_desc, purpose) VALUES (%d, unixepoch("%s"), %d, "%s", "%s");', $arData[$i][0], $sDate, $arData[$i][1]*$iMultiplier, $arData[$i][2], $arData[$i][3])
    				EndIf
    			Next
    			_SQLite_ExecCatchErr($hDB, $sSql)
    		Next
    	Next
    EndFunc
    Alles anzeigen

    Ich hoffe das hilft dir weiter, bzw. gibt dir einen kleinen Anstoß.

  • ConsoleWrite() und Fehlermeldungen darin unter bestimmten Bedingungen

    • Kanashius
    • 26. April 2025 um 15:36
    AutoIt
    For $a = 0 To 144
        For $b = 0 To 144
            ConsoleWrite("Dice: " & $numbers2[$b] & " ----------> " & " Number: " & $numbers1[$b] &@CRLF)
        Next
    Next
    ; 0-144 sind 145 Durchläufe, was ein Index zu groß ist, deshalb die Fehlermeldung "Array variable has incorrect number of subscripts"
    
    For $a = 0 To $numbers2
        For $b = 0 To $numbers1
            ConsoleWrite("Dice: " & $numbers2[$b] & " ----------> " & " Number: " & $numbers1[$b] &@CRLF)
        Next
    Next
    ; $numbers2 und $numbers1 sind Arrays. In den meisten Sprachen fliegt dir das um die Ohren, weil es keine Zahlen sind, in AutoIt passiert das nicht,
    ; stattdessen wird versucht, sie in eine Zahl umzuwandeln. Das geht bei Arrays nicht, also wird 0 zurückgegeben.
    ; For $a = 0 To $numbers2 ist das gleiche wie For $a=0 to 0 => Es läuft genau einmal mit $a=0
    
    For $a = 0 To UBound($numbers2) - 1
        For $b = 0 To UBound($numbers1) - 1
            ConsoleWrite("Dice: " & $numbers2[$b] & " ----------> " & " Number: " & $numbers1[$b] &@CRLF)
        Next
    Next
    ; Es ist alles richtig und es passiert genau das, was dort geschrieben steht, ohne seltsame nebeneffekte.
    ; Du läufts von 0 bis UBound($numbers2)-1 => 0 bis 143 und führst alles in der Schleife 144x aus.
    ; Da du in der Schleife eine weitere Schleife hast, die auch von 0 bis 143 geht und diese für jeden der 144x durchlaufe einmal durchlaufen wird
    ; kommst du auf 144x144 durchläufe der Zeile => ConsoleWrite("Dice: " & $numbers2[$b] & " ----------> " & " Number: " & $numbers1[$b] &@CRLF)
    ; Hier ist es kein Fehler in AutoIt oder beim Programmieren, sondern ein Logik-Fehler, was genau du umsetzen willst
    
    For $a = 0 To 143
        For $b = 0 To 143
            ConsoleWrite("Dice: " & $numbers2[$b] & " ----------> " & " Number: " & $numbers1[$b] &@CRLF)
        Next
    Next
    ; Selbe wie vorher, nur dass du die Größe der Arrays nicht verändern darfst
    
    For $a = 0 To $numbers2[$a]
        For $b = 0 To $numbers1[$b]
            ConsoleWrite("Dice: " & $numbers2[$b] & " ----------> " & " Number: " & $numbers1[$b] &@CRLF)
        Next
    Next
    ; Du gehst von $a=0 bis zu dem Wert, der in $numbers2[$a] steht, also in $numbers2[0] (Im ersten durchlauf)
    ; Da du die Arrays durchmischt, wird dort jedesmal eine andere Zahl stehen, welche auch immer dort hingemischt wurde...
    ; Wenn das zufällig 144 ist, wird das ganze mit ner Fehlermeldung abstürzen
    ; Das ganze ergibt also nicht mal Ansatzweise einen Sinn
    ; Selbes auch für das Beispiel, wo du nochmal 1 abziehst...
    
    
    
    ; Ich bin mir nicht sicher, was genau du machen willst, aber ich hab mal zwei sachen gebastelt, die vermutlich in die Richtung gehen...
    Local $arData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    Local $arData2 = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    
    ConsoleWrite("--------------------------"&@crlf)
    For $i=0 To UBound($arData)-1 Step 1
    	ConsoleWrite($i&": "&$arData[$i]&" - "&$arData2[$i]&@crlf)
    Next
    
    ConsoleWrite("--------------------------"&@crlf)
    For $i=0 To 100
    	Local $iRandom = Random(0, UBound($arData)-1, 1)
    	ConsoleWrite($iRandom&": "&$arData[$iRandom]&@crlf)
    Next
    Alles anzeigen
  • AutoIt-Hackathon #2 CypherEnigma

    • Kanashius
    • 22. April 2025 um 16:16
    AutoIt
    Func _CypherEnigma($sString, $nKlein, $nGross, $nSonder, $nExtra)
    	Local $arLetters = StringToASCIIArray($sString)
    	Local $iExtra = $nExtra
    	For $i=0 To UBound($arLetters)-1 Step 1
    		Local $iCode = $arLetters[$i]
    		If $iCode>64 And $iCode<91 Then
    			$iCode = 65 + Mod($iCode + $nGross + $iExtra - 65, 26)
    		ElseIf $iCode>96 And $iCode<123 Then
    			$iCode = 97 + Mod($iCode + $nKlein + $iExtra - 97, 26)
    		ElseIf $iCode>31 And $iCode<127 Then
    			$iCode -= 32
    			If $iCode>32 Then $iCode-=26
    			If $iCode>38 Then $iCode-=26
    			$iCode = Mod($iCode + $nSonder + $iExtra, 43) + 32
    			If $iCode>64 Then $iCode+=26
    			If $iCode>96 Then $iCode+=26
    		EndIf
    		$arLetters[$i] = $iCode
    		$iExtra += $nExtra
    	Next
    	Return StringFromASCIIArray($arLetters)
    EndFunc   ;==>_CypherEnigma
    Alles anzeigen
  • map fuer ein magisches quadrat und dessen aufloesung

    • Kanashius
    • 19. April 2025 um 22:25

    Ich fand Magic Squares ganz interessant, wollte die aber nicht in einer Ini abspeichern, sondern selbst generieren.
    Bis ich das fertig hatte, hat in der Zwischenzeit Schnuffel schon gepostet, deshalb geh ich auf dein Script mal nicht weiter ein.
    Stattdessen hab ich noch eine Gui dazugebastelt, in der man einen Text eingeben kann und sowohl mit Magic Square verschlüsseln als auch entschlüsseln kann.
    Das ganze arbeitet dabei mit einem Füll-Zeichen, wenn die Anzahl an Text nicht ein ganzes Magic Square füllt.
    Das Trenn-Zeichen kann dabei auch geändert werden. (Wenn es leer gelassen wird, wird jeder Buchstabe einzeln vertauscht, was für ein richtiges durcheinander sorgt :D)

    Vielleicht hat ja noch jemand Spaß daran :)

    AutoIt
    Global $sExampleText = "dieses kleine aber durchaus feine AutoIT test script soll einen total konfus"&@crlf& _
    						"gewirbelten satz durch eine ini map wieder in einen lesbaren string bzw."&@crlf& _
    						"array verwandeln. es basiert auf dem prinzip eines zwoelf mal zwoelf rasters"&@crlf& _
    						"und stellt ein magisches quadrat dar. es ist das einfachste bzw. simpelste"&@crlf& _
    						"magische quadrat was es im internet zu finden gibt. es besteht also"&@crlf& _
    						"aus zwoelf worten in jeweils zwoelf reihen und zwoelf worten in jeweils"&@crlf& _
    						"zwoelf spalten. somit sind es dann insgesamt 144 worte. ich habe das"&@crlf& _
    						"ganze vorher in libre office calc ausrechen lassen wo welches wort stehen"&@crlf& _
    						"muss um dann eine ini datei zu schreiben wo das richtige wort"&@crlf& _
    						"aus dem text eigentlich stehen muss damit es auch einen sinn ergibt."&@crlf& _
    						"AutoIT hilft dann dabei die ganzen woerter zu sortieren. ich finde das"&@crlf& _
    						"immer so toll kleine scripte zu testen und ihr hoffentlich dann auch!"
    
    ; Print a square to console
    ; Local $arSquare = _calcMagicSquare(12)
    ; _printMagicSquare($arSquare)
    
    ; checking if the square generation works:
    ; For $i=0 To 100 Step 1
    ;	 Local $arSquare = _calcMagicSquare($i)
    ;	 If (Not _checkAllOneValue(_getArrayLineSums($arSquare))) Or (Not _checkAllOneValue(_getArrayLineSums($arSquare, True))) Then ConsoleWrite("Magic Square for "&$i&" was wrong."&@crlf)
    ; Next
    
    ; open encrypt/decrypt gui
    _openGui()
    
    Func _openGui()
    	Local $iWidth = 1200, $iHeight=800, $iSpace = 10, $iCtrlHeight=25
    	Local $hGui = GUICreate("Text scrambler", $iWidth, $iHeight)
    	Local $iEditWidth = ($iWidth-($iSpace*3))/2, $iEditHeight = $iHeight-$iSpace*4-$iCtrlHeight*2
    	Local $iWidth4th = ($iWidth-$iSpace*5)/4
    	GUICtrlCreateLabel("Delimeter: ", $iSpace, $iSpace, $iWidth4th, $iCtrlHeight)
    	Local $idInputDelimeter = GUICtrlCreateInput(" ", $iSpace*2+$iWidth4th, $iSpace, $iWidth4th, $iCtrlHeight)
    	GUICtrlCreateLabel("Filler: ", $iSpace*3+$iWidth4th*2, $iSpace, $iWidth4th, $iCtrlHeight)
    	Local $idInputFiller = GUICtrlCreateInput(".", $iSpace*4+$iWidth4th*3, $iSpace, $iWidth4th, $iCtrlHeight)
    	Local $idEditClearText = GUICtrlCreateEdit($sExampleText, $iSpace, $iSpace*2+$iCtrlHeight, $iEditWidth, $iEditHeight)
    	Local $idButtonEncrypt = GUICtrlCreateButton("Encrypt >>", $iSpace, $iHeight-$iSpace-$iCtrlHeight, $iEditWidth, $iCtrlHeight)
    	Local $idEditEncrypted = GUICtrlCreateEdit("", $iSpace*2+$iEditWidth, $iSpace*2+$iCtrlHeight, $iEditWidth, $iEditHeight)
    	Local $idButtonDecrypt = GUICtrlCreateButton("<< Decrypt", $iSpace*2+$iEditWidth, $iHeight-$iSpace-$iCtrlHeight, $iEditWidth, $iCtrlHeight)
    	GUISetState(@SW_SHOW, $hGui)
    	Local $iMsg
    	While 1
    		$iMsg = GUIGetMsg()
    		Switch $iMsg
    			Case -3
    				Exit
    			Case $idButtonEncrypt
    				Local $sDelimeter = GUICtrlRead($idInputDelimeter)
    				Local $sFiller = GUICtrlRead($idInputFiller)
    				Local $sEncrypted = _cryptSquare(GUICtrlRead($idEditClearText), True, $sDelimeter, $sFiller)
    				GUICtrlSetData($idEditEncrypted, $sEncrypted)
    			Case $idButtonDecrypt
    				Local $sDelimeter = GUICtrlRead($idInputDelimeter)
    				Local $sFiller = GUICtrlRead($idInputFiller)
    				Local $sEncrypted = _cryptSquare(GUICtrlRead($idEditEncrypted), False, $sDelimeter, $sFiller)
    				If @error Then MsgBox(16, "Error", "Input length does not match any magic square size.")
    				GUICtrlSetData($idEditClearText, $sEncrypted)
    		EndSwitch
    	WEnd
    EndFunc
    
    Func _cryptSquare($sText, $bEncrypt = True, $sDelimeter=" ", $sFiller = ".")
    	Local $arParts = StringSplit($sText, $sDelimeter, BitOR(1,2))
    	Local $iSize = Sqrt(UBound($arParts))
    	If Mod($iSize, 1)<>0 Then $iSize = Int($iSize+1)
    	If $iSize=2 Then $iSize+=1
    	Local $arSquare = _calcMagicSquare($iSize)
    	If $bEncrypt Then
    		Local $sResult = ""
    		For $i=0 To UBound($arSquare)-1 Step 1
    			For $j=0 To UBound($arSquare)-1 Step 1
    				Local $iVal = $arSquare[$i][$j]
    				If $iVal>UBound($arParts) Then
    					$sResult &= $sFiller
    				Else
    					$sResult &= $arParts[$arSquare[$i][$j]-1]
    				EndIf
    				If $i<UBound($arSquare)-1 Or $j<UBound($arSquare)-1 Then $sResult &= $sDelimeter
    			Next
    		Next
    		Return $sResult
    	Else
    		Local $arResult[UBound($arParts)], $iCount = 0
    		For $i=0 To UBound($arSquare)-1 Step 1
    			For $j=0 To UBound($arSquare)-1 Step 1
    				Local $iIndex = $arSquare[$i][$j]-1
    				If $iCount>UBound($arParts)-1 Then Return SetError(1, 0, -1)
    				If $iIndex<UBound($arResult) Then $arResult[$iIndex] = $arParts[$iCount]
    				$iCount+=1
    			Next
    		Next
    		Local $sResult = ""
    		For $i=0 To UBound($arResult)-1 Step 1
    			$sResult &= $arResult[$i]
    			If $i<UBound($arResult)-1 Then $sResult&=$sDelimeter
    		Next
    		Return $sResult
    	EndIf
    EndFunc
    
    Func _checkAllOneValue(ByRef $arArray)
    	Local $iVal = $arArray[0]
    	For $i=0 To UBound($arArray)-1 Step 1
    		If $arArray[$i]<>$iVal Then Return False
    	Next
    	Return True
    EndFunc
    
    Func _printMagicSquare(ByRef $arSquare, $bShowInfo = True)
    	Local $arSumRight, $arSumBottom
    	If $bShowInfo Then
    		$arSumRight = _getArrayLineSums($arSquare)
    		$arSumBottom = _getArrayLineSums($arSquare, True)
    	EndIf
    	Local $iSize = UBound($arSquare)
    	Local $iMaxLength = StringLen(String($iSize*$iSize))
    	If $bShowInfo Then
    		If StringLen($arSumBottom[UBound($arSumBottom)-1])+1>$iMaxLength Then $iMaxLength=StringLen($arSumBottom[UBound($arSumBottom)-1])+1
    	EndIf
    	Local $sNumberFormat = "%"&$iMaxLength&"d|"
    	For $x=0 To $iSize-1 Step 1
    		_printLine($iSize, $iMaxLength)
    		ConsoleWrite("|")
    		For $y=0 To $iSize-1 Step 1
    			ConsoleWrite(StringFormat($sNumberFormat, $arSquare[$x][$y]))
    		Next
    		If $bShowInfo Then ConsoleWrite(" ="&$arSumRight[$x])
    		ConsoleWrite(@crlf)
    	Next
    	If $bShowInfo Then
    		_printLine($iSize, $iMaxLength)
    		For $x=0 To $iSize-1 Step 1
    			ConsoleWrite(StringFormat("%"&$iMaxLength+1&"s", "="&$arSumBottom[$x]))
    		Next
    		ConsoleWrite(@crlf)
    	EndIf
    EndFunc
    
    ; Last item contains the max sum
    Func _getArrayLineSums(ByRef $arSquare, $bRow=False)
    	Local $iSize = UBound($arSquare)
    	Local $arSum[$iSize+1]
    	For $i=0 To $iSize-1 Step 1
    		Local $iSum = 0
    		For $j=0 To $iSize-1 Step 1
    			If $bRow Then
    				$iSum += $arSquare[$j][$i]
    			Else
    				$iSum += $arSquare[$i][$j]
    			EndIf
    		Next
    		$arSum[$i] = $iSum
    		If $iSum>$arSum[$iSize] Then $arSum[$iSize] = $iSum
    	Next
    	Return $arSum
    EndFunc
    
    Func _printLine($iSegmentCount, $iSegmentLength)
    	Local $sSep = ""
    	For $x=0 To $iSegmentLength-1 Step 1
    		$sSep&="-"
    	Next
    	ConsoleWrite("+")
    	For $y=0 To $iSegmentCount-1 Step 1
    		ConsoleWrite($sSep&"+")
    	Next
    	ConsoleWrite(@crlf)
    EndFunc
    
    ; https://www.iupindia.in/910/IJCM_Magic_Square_Construction_Algorithms34.pdf
    Func _calcMagicSquare($iSize)
    	If $iSize=2 Then Return SetError(1, -1, -1) ; not possible for $iSize=2
    	Local $arSquare[$iSize][$iSize]
    	If $iSize=4 Then
    		Local $arTmp = [[1, 15, 14, 4], [12, 6, 7, 9], [8, 10, 11, 5], [13, 3, 2, 16]] ; algorithm used only once, so why implement it
    		Return $arTmp
    	ElseIf Mod($iSize, 2)=0 Then ; size is even
    		If Mod($iSize, 4)=2 Then
    			Local $iMatMax = ($iSize*$iSize)/4, $iMatSize = $iSize/2
    			Local $arM1 = _calcMagicSquare($iSize/2)
    			; initial square
    			For $i=0 To 1 Step 1
    				For $j=0 To 1 Step 1
    					Local $iAdd = 0
    					If $i=1 And $j=0 Then $iAdd = $iMatMax*3
    					If $i=0 And $j=1 Then $iAdd = $iMatMax*2
    					If $i=1 And $j=1 Then $iAdd = $iMatMax
    					For $x=0 To $iMatSize-1 Step 1
    						For $y=0 To $iMatSize-1 Step 1
    							$arSquare[$x+($i*$iMatSize)][$y+($j*$iMatSize)] = $arM1[$x][$y] + $iAdd
    						Next
    					Next
    				Next
    			Next
    			; swapping around
    			Local $iMatSizeHalf = Int($iMatSize/2)
    			For $x=0 To $iMatSizeHalf-1
    				For $y=0 To $iMatSizeHalf-1
    					_swap($arSquare, $x, $y, $x+$iMatSize, $y)
    				Next
    			Next
    			For $x=$iMatSizeHalf+1 To $iMatSize-1 Step 1
    				For $y=0 To $iMatSizeHalf-1 Step 1
    					_swap($arSquare, $x, $y, $x+$iMatSize, $y)
    				Next
    			Next
    			Local $x=$iMatSizeHalf
    			For $y=1 To $iMatSizeHalf Step 1
    				_swap($arSquare, $x, $y, $x+$iMatSize, $y)
    			Next
    			For $x=0 To $iMatSize-1 Step 1
    				For $y=($iMatSize-$iMatSizeHalf)+1 To $iMatSize-1 Step 1
    					_swap($arSquare, $x, $y+$iMatSize, $x+$iMatSize, $y+$iMatSize)
    				Next
    			Next
    		Else
    			Local $iMatMax = ($iSize*$iSize)/4, $iMatSize = $iSize/2
    			Local $arM1 = _calcMagicSquare($iSize/2)
    			; initial square
    			For $i=0 To 1 Step 1
    				For $j=0 To 1 Step 1
    					Local $iAdd = 0
    					If $i=1 And $j=0 Then $iAdd = $iMatMax*2
    					If $i=0 And $j=1 Then $iAdd = $iMatMax*3
    					If $i=1 And $j=1 Then $iAdd = $iMatMax
    					For $x=0 To $iMatSize-1 Step 1
    						For $y=0 To $iMatSize-1 Step 1
    							$arSquare[$x+($i*$iMatSize)][$y+($j*$iMatSize)] = $arM1[$x][$y] + $iAdd
    						Next
    					Next
    				Next
    			Next
    			If Mod($iMatSize, 4) = 2 Then
    				Local $iMiddleRows = Int($iMatSize/2)+1
    				For $x=$iMiddleRows/2 To $iMatSize-$iMiddleRows/2 Step 1
    					For $y=0 To $iMatSize-1 Step 1
    						_swap($arSquare, $x, $y, $x, $y+$iMatSize)
    					Next
    				Next
    				For $x=$iMiddleRows/2 To $iMatSize-$iMiddleRows/2 Step 1
    					For $y=0 To $iMatSize-1 Step 1
    						_swap($arSquare, $x+$iMatSize, $y, $x+$iMatSize, $y+$iMatSize)
    					Next
    				Next
    			Else
    				Local $iMiddleRows = $iMatSize/2
    				For $x=$iMiddleRows/2 To $iMatSize-$iMiddleRows/2-1 Step 1
    					For $y=0 To $iMatSize-1 Step 1
    						_swap($arSquare, $x, $y, $x, $y+$iMatSize)
    					Next
    				Next
    				For $x=$iMiddleRows/2 To $iMatSize-$iMiddleRows/2-1 Step 1
    					For $y=0 To $iMatSize-1 Step 1
    						_swap($arSquare, $x+$iMatSize, $y, $x+$iMatSize, $y+$iMatSize)
    					Next
    				Next
    			EndIf
    		EndIf
    	Else ; size is odd
    		Local $iN = 1, $x=0, $y=Int($iSize/2), $iLimit = $iSize*$iSize
    		While $iN<=$iLimit
    			If $arSquare[$x][$y]=0 Then
    				$arSquare[$x][$y] = $iN
    				$iN+=1
    				$x -= 1
    				If $x<0 Then $x=$iSize-1
    				$y -= 1
    				If $y<0 Then $y=$iSize-1
    			Else
    				$x = Mod($x+2, $iSize)
    				$y = Mod($y+1, $iSize)
    			EndIf
    		WEnd
    	EndIf
    	Return $arSquare
    EndFunc
    
    Func _swap(ByRef $arSquare, $x1, $y1, $x2, $y2)
    	Local $iTmp = $arSquare[$x1][$y1]
    	$arSquare[$x1][$y1] = $arSquare[$x2][$y2]
    	$arSquare[$x2][$y2] = $iTmp
    EndFunc
    Alles anzeigen

    Referenz:
    Paper mit dem Algorithmus für die Berechnung der Magic Squares: https://www.iupindia.in/910/IJCM_Magic…lgorithms34.pdf

  • array(s) nach daten durchsuchen und zuordnen und damit dann ein neues array anlegen

    • Kanashius
    • 18. April 2025 um 15:08
    Zitat von bankesbusters

    ich habe allerdings noch einige fragen:

    du (und auch viele andere), ja teilweise sogar in den AutoIT hilfe-seiten und den darin enthaltenen beispielen arbeiten unglaublich oft und viel mit 'Func'. ich sehe den vorteil nicht wirklich davon, weil es macht alles nur (meiner meinung nach) unuebersichtlicher. ... du hast dann irgendwo im script "Func _example()" und musst dann erst suchen im script wo die func abgelegt ist (meist ganz unten) und wenn man auf func verzichtet, sieht man den kompletten notwendigen code an der stelle wo er abgearbeitet wird bzw. werden soll. ich sehe den vorteil nicht in der nutzung von funktionen. also wo ist der vorteil?

    jetzt schreibe bitte nicht so etwas wie: "du kannst funktionen mehrmals nutzen an verschiedenen stellen" ... jetzt mal ehrlich, wie oft brauchst du ein und die selbe funktion in einem einzigen script? ich habe eine funktion noch nie ein zweites mal verwendet, oder wenn ich sie ein zweites mal verwendet werden musste, dann musste in der funktion irgend eine kleinigkeit geaendert werden, welches die nutzung der selben funktion ebenfalls unmoeglich machte. gebe mir doch mal bitte ein beispiel wo exakt die gleiche funktion sinnvoll mehrmals genutzt wird in einem script unabhaengig vom user oder usereingaben. geht doch gar nicht, oder doch?

    jedenfalls meine (test)scripte arbeiten alle nach einem schema: wenn dies, dann das und dann jenes und danach etwas anderes. sprich nur wenn prozess 'a' ausgefuehrt wird kann prozess 'b' beginnen usw.

    Naja... es reicht ein Blick in dein Script, warum Funktionen Sinn machen:
    Was ist denn _ArrayDisplay, _ArrayShuffle, ... Genau: Funktionen, die du mehrfach nutzt... wär jetzt doof, wenn du jedesmal den Code von _ArrayShuffle stattdessen dort hinschreiben würdest, oder?

    Spoiler anzeigen

    Der sieht nämlich so aus:

    AutoIt
    Func _ArrayShuffle(ByRef $aArray, $iStart_Row = 0, $iEnd_Row = 0, $iCol = -1)
    
    	; Fisher-Yates algorithm
    
    	If $iStart_Row = Default Then $iStart_Row = 0
    	If $iEnd_Row = Default Then $iEnd_Row = 0
    	If $iCol = Default Then $iCol = -1
    
    	If Not IsArray($aArray) Then Return SetError(1, 0, -1)
    	Local $iDim_1 = UBound($aArray, $UBOUND_ROWS)
    	If $iEnd_Row = 0 Then $iEnd_Row = $iDim_1 - 1
    	If $iStart_Row < 0 Or $iStart_Row > $iDim_1 - 1 Then Return SetError(3, 0, -1)
    	If $iEnd_Row < 1 Or $iEnd_Row > $iDim_1 - 1 Then Return SetError(3, 0, -1)
    	If $iStart_Row > $iEnd_Row Then Return SetError(4, 0, -1)
    
    	Local $vTmp, $iRand
    	Switch UBound($aArray, $UBOUND_DIMENSIONS)
    		Case 1
    			For $i = $iEnd_Row To $iStart_Row + 1 Step -1
    				$iRand = Random($iStart_Row, $i, 1)
    				$vTmp = $aArray[$i]
    				$aArray[$i] = $aArray[$iRand]
    				$aArray[$iRand] = $vTmp
    			Next
    			Return 1
    		Case 2
    			Local $iDim_2 = UBound($aArray, $UBOUND_COLUMNS)
    			If $iCol < -1 Or $iCol > $iDim_2 - 1 Then Return SetError(5, 0, -1)
    			Local $iCol_Start, $iCol_End
    			If $iCol = -1 Then
    				$iCol_Start = 0
    				$iCol_End = $iDim_2 - 1
    			Else
    				$iCol_Start = $iCol
    				$iCol_End = $iCol
    			EndIf
    			For $i = $iEnd_Row To $iStart_Row + 1 Step -1
    				$iRand = Random($iStart_Row, $i, 1)
    				For $j = $iCol_Start To $iCol_End
    					$vTmp = $aArray[$i][$j]
    					$aArray[$i][$j] = $aArray[$iRand][$j]
    					$aArray[$iRand][$j] = $vTmp
    				Next
    			Next
    			Return 1
    		Case Else
    			Return SetError(2, 0, -1)
    	EndSwitch
    
    EndFunc   ;==>_ArrayShuffle
    Alles anzeigen

    Ein weiterer wichtiger Punkt ist nicht nur die Wiederverwendbarkeit (was in meinem Script auch schon mehrfach auftaucht: _readIniToMap wird 2x genutzt, _getRoom 3x,... ) sondern auch die Struktur.
    Je größer ein Programm wird, desto unübersichtlicher wird es. Deshalb gibt es auch so als Richtwert: Wenn ein Codeabschnitt (auch in einer Funktion) mehr als so ca. 30 Zeilen hat sollte er in eine eigene Funktion (gibt natürlich ausnahmen, aber in die Richtung geht es).
    Die Aufgabe wird dadurch in mehrere Abschnitte unterteilt, was das ganze übersichtlicher macht.
    Wenn jemand sich neuen Code von jemand anders anschaut um den zu Verstehen ist es halt übersichtlicher zu sehen:

    Code
    Func _processData()
    	Local $arData = _readData()
    	$arData = _removeDuplicates($arData)
    	$arData = _multiplyDataValues($arData)
    	_saveData($arData)
    EndFunc

    Wo ich abstrahiert erfahre, was gemacht wird. Einlesen->Duplikate entfernen->Daten multiplizieren (als Beispiel für z.B. Zahlen)->Ergebnis speichern.
    Insbesondere, wenn ich später mal was verändern will, weiß ich direkt, in welchen Abschnitt ich gehen muss um ihn mir anzuschauen.
    Ich habe nicht direkt 200 Zeilen Code und muss rausfinden, wo jetzt was passiert, sondern kann direkt zu dem Abschnitt/der Funktion gehen, die ich verändern muss.

    Dazu kommt, dass Funktionen normalerweise auch genutzt werden um bestimmte Aufgaben zu erledigen.
    Am besten ist es dabei, wenn die Funktion alles, was sie braucht als Parameter bekommt und auf keine Globalen Variablen oder ähnliches zugreifen muss.
    Ich kann dann eine Funktion schreiben, die z.B. zwei Matritzen multipliziert und übergebe dort die beiden Matrizen als Parameter.
    Ich habe dann ein geschlossenes System, das genau eine Aufgabe hat: Die beiden Matritzen-Parameter zu multiplizieren und kann genau schauen, wie das passiert und ggf. Fehler korrigieren, ohne das ich das gesamte Script kennen muss, weil ich keine Ahnung hab, wo die Variable denn jetzt herkommt, die 100 Zeilen zuvor erstellt wurde, 10x zwischendurch verändert wird und dann am Ende bei meiner Multiplikation landet.

    Und wenn man immer mit diesem Stil programmiert macht man das natürlich auch in kleinen 50 Zeilen programmen, auch wenn es da nicht unbedingt notwendig wäre.
    Man weiß ja auch nie, ob das Script vielleicht wächst und immer größer erweitert wird und dann steht man am Ende mit 1000 Zeilen durcheinander da ;)

    Ein weiterer Punkt: Es trennt die verschiedenen Variablen voneinandern.
    Variablen sind immer in einem Bereich gülitig. Schreibst du sie einfach in die Datei, gilt sie überall, du kannst also dort z.B. $arData definieren und überall darauf zugreifen.
    Wenn man aber nicht aufpasst kann in größeren Scripten schnell vergessen, dass man den Variable Namen schonmal genutzt hat.
    Dann überschreibt man ausversehen diese Variable und hat dort was komplett anderes drin stehen, als man denkt, was zu Fehlern führen kann, die versteckt sind und deshalb sehr lange brauchen, bis man das Problem findet.
    Nutzt man Funktionen und Lokale Variablen, sind die nur in der Funktion gültig und die Wahrscheinlichkeit für irgendwelche Namens-Konflikte ist erheblich geringer.

  • array(s) nach daten durchsuchen und zuordnen und damit dann ein neues array anlegen

    • Kanashius
    • 17. April 2025 um 20:35

    Doch, die Map ist immernoch die beste Möglichkeit, um den Raum von einer Namen/Monats kombination zu ermitteln.
    Wie du die Namen/Monate speicherst und in welcher Reihenfolge kannst du dir frei aussuchen.

    Wenn du diese Funktion in mein Script von vorher einfügst sollte es das sein, was du willst (wenn ich es jetzt richtig verstanden hab)

    AutoIt
    #include <Array.au3>
    _example2()
    
    Func _example2()
    	Local $mData = _readIniToMap("loesung.ini", "Data")
    	Local $sMonth = 'Januar Februar Maerz April Mai Juni Juli August September Oktober November Dezember'
    	Local $sNames = 'Paul Ursula Robert Marion Peter Nadine Stefan Esther Oliver Evelyn Michael Doris'
    	Local $arMonth = StringSplit($sMonth, " ", BitOR(1, 2))
    	Local $arNames = StringSplit($sNames, " ", BitOR(1, 2))
    	_ArrayShuffle($arMonth, 0,11)
    	_ArrayShuffle($arNames, 0,11)
    	Local $arResult[UBound($arMonth)][3]
    	For $i=0 To UBound($arMonth)-1 Step 1
    		$arResult[$i][0] = $arNames[$i]
    		$arResult[$i][1] = $arMonth[$i]
    		Local $sRoom = _getRoom($mData, $arNames[$i], $arMonth[$i])
    		If $sRoom<>-1 Then $arResult[$i][2] = "Raum "&$sRoom
    	Next
    	_ArrayDisplay($arResult)
    EndFunc
    Alles anzeigen
  • array(s) nach daten durchsuchen und zuordnen und damit dann ein neues array anlegen

    • Kanashius
    • 17. April 2025 um 15:53

    Wenn ich deine Beschreibung richtig verstanden habe, ist das Ziel ein Programm, in dem du den Namen und Monat auswählst und dann den zugehörigen Raum angezeigt bekommst.
    Ich würde in dem Fall nicht mit Arrays, sondern mit Maps arbeiten. Die sind extra dafür da, Daten so abzulegen, dass man mit Schlüsselwörtern (Name/Monat) schnell darauf zugreifen kann:

    AutoIt
    _example()
    
    _startGui()
    
    Func _example()
    	Local $mData = _readIniToMap("loesung.ini", "Data")
    	Local $arNames = ["Paul", "Ursula", "Robert", "Marion", "Peter", "Nadine", "Stefan", "Esther", "Oliver", "Evelyn" ,"Michael", "Doris"]
    	Local $arMonth = ["Januar", "Februar", "Maerz", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
    	For $i=0 To UBound($arNames)-1 Step 1
    		For $j=0 To UBound($arMonth)-1 Step 1
    			ConsoleWrite(StringFormat("%-10s is in %-10s in Room: %s", $arNames[$i], $arMonth[$j], _getRoom($mData, $arNames[$i], $arMonth[$j]))&@crlf)
    		Next
    	Next
    EndFunc
    
    Func _getRoom(ByRef $mData, $sName, $sMonth)
    	If MapExists($mData, $sName) Then
    		If MapExists($mData[$sName], $sMonth) Then Return $mData[$sName][$sMonth]
    	EndIf
    	Return -1
    EndFunc
    
    Func _readIniToMap($sFile, $sSection)
    	Local $arSec = IniReadSection($sFile, $sSection)
    	Local $mData[]
    	For $i=1 To UBound($arSec)-1 Step 1
    		;Local $arValue = StringSplit($arSec[$i][1], "|", BitOR(1, 2))
    		;If UBound($arValue)<3 Then ContinueLoop
    		Local $arValue = StringRegExp($arSec[$i][1], "([^|]*)\|(Januar|Februar|Maerz|April|Mai|Juni|Juli|August|September|Oktober|November|Dezember){1}\|Raum(\d+)", 1)
    		If @error Then
    			ConsoleWrite(StringFormat('Error reading IniKey "%s" with Value "%s"', $arSec[$i][0], $arSec[$i][1])&@crlf)
    			ContinueLoop
    		EndIf
    
    		If MapExists($mData, $arValue[0]) Then
    			$mData[$arValue[0]][$arValue[1]] = $arValue[2]
    		Else
    			Local $mEntry[]
    			$mEntry[$arValue[1]] = $arValue[2]
    			$mData[$arValue[0]] = $mEntry
    		EndIf
    	Next
    	Return $mData
    EndFunc
    
    Func _startGui()
    	Local $mData = _readIniToMap("loesung.ini", "Data")
    	Local $arNames = MapKeys($mData)
    	Local $sNames = ""
    	For $i=0 To UBound($arNames)-1 Step 1
    		$sNames&=$arNames[$i]
    		If $i<>UBound($arNames)-1 Then $sNames&="|"
    	Next
    	Local $sMonth = "Januar|Februar|Maerz|April|Mai|Juni|Juli|August|September|Oktober|November|Dezember"
    	Local $iWidth = 300, $iHeight = 100, $iSpace = 10, $iCtrlHeight = 20
    	Local $hGui = GUICreate("Room searcher", $iWidth, $iHeight)
    	Local $idComboNames = GUICtrlCreateCombo("", $iSpace, $iSpace, $iWidth-$iSpace*2, $iCtrlHeight)
    	GUICtrlSetData($idComboNames, $sNames)
    	Local $idComboMonth = GUICtrlCreateCombo("", $iSpace, $iSpace*2+$iCtrlHeight, $iWidth-$iSpace*2, $iCtrlHeight)
    	GUICtrlSetData($idComboMonth, $sMonth)
    	Local $idLabelRoom = GUICtrlCreateLabel("Raum: ", $iSpace, $iSpace*3+$iCtrlHeight*2, $iWidth-$iSpace*2, $iCtrlHeight)
    	GUISetState(@SW_SHOW, $hGui)
    	While True
    		Local $iMsg = GUIGetMsg()
    		Switch $iMsg
    			Case -3
    				Exit
    			Case $idComboNames, $idComboMonth
    				Local $sRoom = _getRoom($mData, GUICtrlRead($idComboNames), GUICtrlRead($idComboMonth))
    				If $sRoom<>-1 Then
    					GUICtrlSetData($idLabelRoom, "Raum: "&$sRoom)
    				Else
    					GUICtrlSetData($idLabelRoom, "Raum: ?")
    				EndIf
    		EndSwitch
    	WEnd
    EndFunc
    Alles anzeigen

    Ich habe hier eine Funktion erstellt, welche die Ini in eine Map einliest. Bei einer Map wird anders als bei einem Array, nicht mit einer Zahl als Index auf einen Wert zugegriffen, sondern stattdessen mit beliebigen Daten. Hier mit dem Namen oder dem Monat.
    Dabei ist das ganze hier in zwei Maps verschachtelt (wie ein 2D-Array).
    Eine Map, bei der man mit dem Namen eine weitere Map bekommt, in der für jeden Monat der Raum steht.

    Code
    Local $mData[]
    $mData["Paul"] = "Something"
    $mData["Mustermann"] = "Something else"
    ; dann kann man mit
    ConsoleWrite("Paul: "&$mData["Paul"]&@crlf)
    ; auf die Daten zugreifen.
    ; in dem Code oben habe ich das ganze beim einlesen der Ini gemacht (_readIniToMap):
    Local $mPersonData[]
    $mPersonData["Januar"] = "Raum 103"
    $mPersonData["Februar"] = "Raum 104"
    $mData["Mustermann"] = $mPersonData
    ; Dann kann so auf die Infos zugegriffen werden:
    ConsoleWrite("Mustermann im Januar: "&$mData["Mustermann"]["Januar"]&@crlf)
    Alles anzeigen

    Das ganze hat auch den Vorteil, dass ich alle Namen aus der $mData Map mit MapKeys($mData) auslesen kann und dann ein Array mit allen Namen aus der Ini-Datei habe, was ich in dem Code nutze um die ComboBox mit Namen zu befüllen.
    Da sich die Monate nicht ändern, musst du das Script also nie anpassen, wenn du eine weitere Person hinzufügst. Es reicht die Datei in der Ini hinzuzufügen.

    Du hast übrigens in der Ini bei einigen Nutzern "Mai" und bei anderen "May" als Monat angegeben, deshalb wird der Raum für manche Nutzer im Mai nicht gefunden.
    Deshalb hab ich mal beim einlesen der Ini das StringSplit mit einem RegExp ausgetauscht. Dadurch wird die Ini geprüft, ob die Eingabe richtig ist, oder ob irgendwo ein Fehler ist und der Fehler ggf. ausgegeben.

  • Problem mit einer For-To-Next-Schleife. (Verstaendisprobleme)

    • Kanashius
    • 17. April 2025 um 14:45

    Hey, bakesbusters,

    Das Ergebnis ist richtig (Die Verwendung von For $z = 0 To UBound($nummern2, 2) - 1 ), das warum ist aber komplett falsch.
    Es hat garnichts mit 3D-Arrays zu tun, es wird auch nichts deklariert.
    UBound ist einfach eine Funktion, die die Anzahl der Elemente im Array ausgibt.
    Bei einem 1D-Array ist das wie eine Liste, wo UBound($arData) die Anzahl der Elemente in der Liste zurückgibt:

    Code
    Local $arData = ["Erstes Element", "Zweites Element", "Drittes Element"]
    1. Erstes Element	=> $arData[0]
    2. Zweites Element	=> $arData[1]
    3. Drittes Element	=> $arData[2]
    Ubound($arData) gibt also 3 zurück

    Ein 2D-Array ist dagegen wie eine Tabelle, wo Ubound($arData) die Anzahl der Zeilen zurückgibt und Ubound($arData, 2) die Anzahl der Spalten.

    Code
    Local $arData[3][2] = [["Zeile 1 Spalte 1", "Zeile 1 Spalte 2"], ["Zeile 2 Spalte 1", "Zeile 2 Spalte 2"], ["Zeile 3 Spalte 1", "Zeile 3 Spalte 2"]]
    +-----------------------------------+----------------------------------+
    |  Zeile 1 Spalte 1 ($arData[0][0]) | Zeile 1 Spalte 2 ($arData[0][1]) |
    +-----------------------------------+----------------------------------+
    |  Zeile 2 Spalte 1 ($arData[1][0]) | Zeile 2 Spalte 2 ($arData[1][1]) |
    +-----------------------------------+----------------------------------+
    |  Zeile 3 Spalte 1 ($arData[2][0]) | Zeile 3 Spalte 2 ($arData[2][1]) |
    +-----------------------------------+----------------------------------+
    Ubound($arData) gibt also 3 zurück, weil es 3 Zeilen gibt
    Ubound($arData) gibt also 2 zurück, weil es 2 Spalten gibt

    Als "Deklaration" bezeichnet man übrigens nur die Angabe ("Deklaration") der Variable. Also z.B.:

    Code
    Local $sData
    Local $arData[2][3]

    Dabei wird nur festgelegt, dass es die Variable gibt (und in den meisten Sprachen auch welchen Typ sie hat, also wie viel Arbeitsspeicher sie benötigt). Dabei wird auch die Größe des Arrays angegeben.

    Als "Definition" oder "Zuweisung" wird es bezeichnet, wenn man einer Variable dabei einen Wert zuweist:

    Code
    Local $sData = "Ein schöner String"
    Local $arData = ["Ein", "schönes", "Array"]

    Dabei kann man z.B. die Größen-Angabe des Arrays weglassen, weil der Compiler sich die Größe durch die Zuweisung direkt selbst ableiten kann.

    Ubound verändert das Array also überhaupt nicht. Es liest nur die Größe aus und gibt sie zurück, damit man damit weiterarbeiten kann.

  • Problem mit einer For-To-Next-Schleife. (Verstaendisprobleme)

    • Kanashius
    • 16. April 2025 um 16:17

    Hier einmal eine Ausführliche Erklärung der For-Schleife und deiner Schwierigkeiten:

    AutoIt
    ; Wenn du das Array direkt zuweist musst du die Größe nicht angeben, die leitet sich aus der Zuweisung automatisch ab
    Local $arNumbers = [[72,87,84], [69,79,79], [76,82,68], [76,76,65], [79,68,89]]
    
    ; Die Größe kann mit Ubound abgefragt werden. Der erste Parameter ist das Array und der zweite die Dimension (Standard, wenn nicht angegeben ist 1)
    ConsoleWrite("2D-Array size: $arNumbers["&UBound($arNumbers)&"]["&UBound($arNumbers, 2)&"]"&@crlf)
    
    ; Eine For-Schleife definiert eine Variable, die mit jedem durchlauf verändert wird (normal um 1 erhöht) und das solange, bis die Variable einen Wert erreicht.
    ; Dabei wird der Start und das Ende angegeben (Hier ist 0 der Start und 10 das Ende).
    ConsoleWrite("-----------"&"For Loop 1"&"-----------"&@crlf)
    For $i=0 To 10
    	ConsoleWrite("Iteration: "&$i&@crlf)
    Next
    
    ; Durch das angeben von Step kann auch festgelegt werden, um wie viel sich die Variable verändern soll.
    ConsoleWrite("-----------"&"For Loop 2"&"-----------"&@crlf)
    For $i=2 To 10 Step 2
    	ConsoleWrite("Iteration: "&$i&@crlf)
    Next
    
    ; Die Werte können dabei auch negativ sein.
    ConsoleWrite("-----------"&"For Loop 3"&"-----------"&@crlf)
    For $i=10 To -10 Step -2
    	ConsoleWrite("Iteration: "&$i&@crlf)
    Next
    
    ; Das kann man dann auch nutzen, um über ein Array zu iterieren.
    ; Da der Index (das zwischen den []) für den Zugriff auf ein Array bei 0 anfängt ist der letzte Index dementsprechend die Größe des Arrays-1
    ; Hier starten wir also bei 0 und wollen bis 3 gehen um alle 4 Werte im Array auszugeben. 0 ist der Anfang und die Größe des Arrays ist 4 ( Ubound($ar1DExample) ).
    ; Es soll aber nicht von 0 bis 4, sondern nur von 0 bis 3 iteriert werden, weil der Index 4 nicht existiert (Array variable has incorrect number of subscripts...).
    ; Also nehmen wir die Größe und ziehen 1 ab: Ubound($ar1DExample)-1, was deshalb das Ziel der For-Schleife ist.
    ConsoleWrite("-----------"&"Iterate Array 1"&"-----------"&@crlf)
    Local $ar1DExample = [11,22,33,44]
    For $i=0 To UBound($ar1DExample)-1 Step 1
    	ConsoleWrite("Access $ar1DExample["&$i&"]: "&$ar1DExample[$i]&@crlf)
    Next
    
    ; Wollen wir jetzt das 2D-Array von oben ($arNumbers) iterieren, müssen wir also erst eine For-Schleife für den ersten Index schreiben und dann für den zweiten Index.
    ; Also bleibt die äußere For-Schleife genauso wie vorher, aber bei der zweiten (inneren) For-Schleife brauchen wir eine andere Variable und das Ziel ist auch nicht mehr
    ; die Größe der ersten Dimension ( UBound($arNumbers) ), sondern die Größe der zweiten Dimension ( UBound($arNumbers, 2) ).
    ; Das war übrigens auch der Fehler, der dir bei deinem Beispiel passiert ist.
    ; Du bist sowohl bei der ersten loop, als auch bei der zweiten von 0 bis 4 iteriert, statt bei der inneren Schleife von 0 bis 2 zu iterieren.
    ; Deshalb kam dann auch die Fehlermeldung, dass du auf Werte außerhalb des Arrays zugreifen willst.
    ; Das Problem bei dem anderen Beispiel aus deinem Post ist, dass du auf $nummern2[$y] zugreifen willst.
    ; Die Variable $nummern2 ist aber ein 2D-Array, du MUSST also den zweiten Index angeben ( $nummern2[$y][$z] ), ansonsten bekommst du die Fehlermeldung:
    ; Array variable ... subscript dimension range exceeded.
    ConsoleWrite("-----------"&"Iterate Array 2"&"-----------"&@crlf)
    ; Local $arNumbers = [[72,87,84], [69,79,79], [76,82,68], [76,76,65], [79,68,89]]
    For $i=0 To UBound($arNumbers)-1 Step 1
    	For $j=0 To UBound($arNumbers, 2)-1 Step 1
    		ConsoleWrite("Access $arNumbers["&$i&"]["&$j&"]: "&$arNumbers[$i][$j]&@crlf)
    	Next
    Next
    
    ; Das gleiche gilt auch für 3D-Arrays. Einfach eine Weitere For-Schleife, die über die dritte Dimension iteriert.
    ConsoleWrite("-----------"&"Iterate Array 3"&"-----------"&@crlf)
    Local $ar3DExample = [[[1, 2, 3], [7, 8, 9]], [[10, 20, 30], [70, 80, 90]]]
    For $i=0 To UBound($ar3DExample)-1 Step 1
    	For $j=0 To UBound($ar3DExample, 2)-1 Step 1
    		For $k=0 To UBound($ar3DExample, 3)-1 Step 1
    			ConsoleWrite("Access $ar3DExample["&$i&"]["&$j&"]["&$k&"]: "&$ar3DExample[$i][$j][$k]&@crlf)
    		Next
    	Next
    Next
    
    ; Ich bin mir auch nicht sicher, warum du in deinem Beispiel das ganze als String umschreiben und dann mit Execute ausführen willst.
    ; Das sorgt nur für unnötig viele Operationen.
    ; Du kannst einfach iterieren und die Funktion für jede Variable aufrufen.
    ConsoleWrite("-----------"&"Array - Int to Char"&"-----------"&@crlf)
    Local $arChars[UBound($arNumbers)][UBound($arNumbers, 2)]
    Local $arWords[UBound($arNumbers)]
    Local $sSentence = ""
    For $i=0 To UBound($arNumbers)-1 Step 1
    
    	Local $sWord = ""
    
    	; Iteriere Buchstaben
    	For $j=0 To UBound($arNumbers, 2)-1 Step 1
    		$arChars[$i][$j] = Chr($arNumbers[$i][$j])
    		ConsoleWrite("Access ["&$i&"]["&$j&"]: "&$arNumbers[$i][$j]&" >> "&$arChars[$i][$j]&@crlf)
    		$sWord &= $arChars[$i][$j]
    	Next
    
    	$arWords[$i] = $sWord
    	ConsoleWrite("Access $arWords["&$i&"]: "&$arWords[$i]&@crlf)
    
    	$sSentence &= $arWords[$i]
    	; Füge Leerzeichen hinzu, wenn es nicht das letzte Wort ist
    	If $i<UBound($arNumbers)-1 Then $sSentence &= " "
    Next
    ConsoleWrite("Sentence: "&$sSentence&@crlf)
    
    
    ; Kommen wir zum wichtigsten, wenn du solche Probleme selbst lösen möchtest:
    ; Lass dir alle Infos ausgeben.
    ; Ein paar ConsoleWrite ausgaben der Variablen würden dir das Problem zeigen
    ConsoleWrite("-----------"&"Problemsolving"&"-----------"&@crlf)
    Global $nummern2[5][3] = [[72,87,84],[69,79,79],[76,82,68],[76,76,65],[79,68,89]]
    Global $pre = "Chr("
    Global $back =")"
    For $y = 0 To UBound($nummern2) - 1
        For $z = 0 To UBound($nummern2) - 1
    		ConsoleWrite("Access: $nummern2["&$y&"]["&$z&"]: ")
    		ConsoleWrite($nummern2[$y][$z]&@CRLF)
    		$nummern2[$y][$z] = $pre & $nummern2[$y][$z] & $back
    		$nummern2[$y][$z] = Execute($nummern2[$y][$z])
        Next
    Next
    ; Die Fehlermeldung folgt auf der Ausgabe => Access: $nummern2[0][3]
    ; Dabei ist 3 größer als $nummern2[5][3] die Größe-1 der zweiten Dimension (3-1=2)
    Alles anzeigen

    Ich hoffe, das hilft dir weiter :)

  • daten aus einer ini datei in ein array[x][x] nach vorgaben umwandeln? möglich? wie?

    • Kanashius
    • 13. April 2025 um 15:13

    Und zum Wiederverwenden als Funktion könnte man es so machen:

    AutoIt
    ConsoleWrite("-------------Array-------------"&@crlf)
    Local $arData = _iniSectionToArray("shortlist.ini", "Data")
    ; Display data
    For $i=0 To UBound($arData)-1 Step 1
    	ConsoleWrite(StringFormat("%-10s %-9s %-8s\r\n", $arData[$i][0], $arData[$i][1], $arData[$i][2]))
    Next
    
    ConsoleWrite("--------------Map--------------"&@crlf)
    Local $mData = _iniToMap("shortlist.ini")
    ; Display data
    For $sKey In MapKeys($mData)
    	ConsoleWrite("-----Section "&$sKey&"-----"&@crlf)
    	Local $mSection = $mData[$sKey]
    	For $sSecKey In MapKeys($mSection)
    		ConsoleWrite($sSecKey&": "&$mSection[$sSecKey]&@crlf)
    	Next
    Next
    
    ConsoleWrite("---------Map Processed---------"&@crlf)
    Local $mDataProc = _iniToMap("shortlist.ini", "_processValueData")
    ; Display data
    For $sKey In MapKeys($mDataProc)
    	ConsoleWrite("-----Section "&$sKey&"-----"&@crlf)
    	Local $mSection = $mDataProc[$sKey]
    	For $sSecKey In MapKeys($mSection)
    		Local $arValue = $mSection[$sSecKey]
    		ConsoleWrite(StringFormat("%-5s: %-10s %-9s %-8s\r\n", $sSecKey, $arValue[0], $arValue[1], $arValue[2]))
    	Next
    Next
    
    Func _iniSectionToArray($sFile, $sSection)
    	Local $arData = IniReadSection($sFile, $sSection)
    	Local $arResult[UBound($arData)-1][3]
    	For $i=1 To UBound($arData)-1 Step 1
    		Local $arLine = StringSplit($arData[$i][1], "|", BitOR(1, 2))
    		If UBound($arLine)<3 Then Return SetError(1, 0, -1)
    		$arResult[$i-1][0] = $arLine[0]
    		$arResult[$i-1][1] = $arLine[1]
    		$arResult[$i-1][2] = $arLine[2]
    	Next
    	Return $arResult
    EndFunc
    
    Func _iniToMap($sFile, $sProcessDataCallback = Default)
    	Local $mResult[]
    	Local $arSections = IniReadSectionNames($sFile)
    	For $i=1 To UBound($arSections)-1 Step 1
    		Local $mSection[]
    		Local $arData = IniReadSection($sFile, $arSections[$i])
    		For $j=1 To UBound($arData)-1 Step 1
    			If $sProcessDataCallback<>Default Then
    				$mSection[$arData[$j][0]] = Call($sProcessDataCallback, $arData[$j][1])
    			Else
    				$mSection[$arData[$j][0]] = $arData[$j][1]
    			EndIf
    		Next
    		$mResult[$arSections[$i]] = $mSection
    	Next
    	Return $mResult
    EndFunc
    
    Func _processValueData($sValue)
    	Return StringSplit($sValue, "|", BitOR(1, 2))
    EndFunc
    Alles anzeigen

    Ich hab noch eine Funktion hinzugefügt, die alls Sections der Ini einliest und in eine Map speichert. Dabei kann auch eine Funktion angegeben werden (z.B. "_ProcessValueData") um die Value weiter zu verarbeiten (hier z.B. in ein Array umzuwandeln).
    Die Ausgabe hab ich extra manuell gemacht, um ein Beispiel zu geben, wie man das benutzen kann.

  • AutoIt Hackathon #1 Mitarbeiter-ID abgeschlossen

    • Kanashius
    • 30. März 2025 um 21:30
    AutoIt
    Func _CreateID($aUserdata)
    	Local $Return
    	Local $Return = StringLeft(StringReplace($aUserdata[2], "-", ""), 5)
    	While StringLen($Return)<5
    		$Return &= "9"
    	WEnd
    	Local $arBirthDate = StringRegExp($aUserdata[3], "(\d+).(\d+).\d{2}(\d)(\d)", 1)
    	$Return &= $arBirthDate[2]
    	If $aUserdata[4]="M" Then
    		$Return &= $arBirthDate[1]
    	Else
    		$Return &= Int($arBirthDate[1])+50
    	EndIf
    	$Return &= $arBirthDate[0]
    	$Return &= $arBirthDate[3]
    	$Return &= StringLeft($aUserdata[0], 2)
    	Local $sVName2 = StringLeft($aUserdata[1], 2)
    	While StringLen($sVName2)<2
    		$sVName2 &= "9"
    	WEnd
    	$Return &= $sVName2
    	Local $iChecksum = 0
    	Local $arChars = StringSplit($Return, "", 1+2)
    	For $i=0 To UBound($arChars)-1 Step 1
    		$iChecksum += Asc($arChars[$i])
    	Next
    	While StringLen($iChecksum)>1
    		Local $arLetters = StringSplit($iChecksum, "", 1+2)
    		Local $iNewSum = 0
    		For $i=0 To UBound($arLetters)-1 Step 1
    			$iNewSum += Int($arLetters[$i])
    		Next
    		$iChecksum = $iNewSum
    	WEnd
    	$Return &= $iChecksum
    	Return $Return
    EndFunc   ;==>_CreateID
    Alles anzeigen
  • Was ist eure Präferenz: "light mode" oder "dark mode" bei Software (egal ob Web oder Desktop)?

    • Kanashius
    • 14. März 2025 um 21:05
    Zitat

    Ich persönlich kann auch nichts mit einem Darkmode anfangen...kein einziges Printmedium/Buch ist lesbarer im Darkmode, mir zumindest ist auch nicht ein einziges relevantes bekannt!

    Ich lese fast ausschließlich ebooks und diese auch nur im darkmode. Ich lese meistens Abends vorm schlafen und wenn mir da der Helle (Smatphone-)Bildschirm ins Gesicht leuchten würde, wäre es mit der eventuellen Müdigkeit aber schwer.

    Und auch was Andy sonst so ausführt sind halt alles helle Umgebungen. Wenn es eh schon hell ist brauch ich keinen Darkmode. Wenn ich aber am PC sitze bin ich normal in einer dunkleren Umgebung und will halt nicht angestrahlt werden. Da dürfte Schnuffels beobachtung also vermutlich zutreffen. Lightmode nutzer machen sich im Zweifel lieber die ganze Umgebung hell, damit die hellen Bildschirme nicht stören.

    Ich bin froh, dass es sich langsam durchsetzt, dass light und darkmode unterstützt wird. (Auch wenn viele Webseiten das leider noch nicht haben.). Ich hoffe ja, dass auch bei PDFs langsam mal der Darkmode auftaucht (wär cool, wenn per Standard die Usereinstellung gilt, diese aber vom PDF "überschrieben" werden kann, wenn die Darstellung im darkmode nicht funktioniert)

  • Was ist eure Präferenz: "light mode" oder "dark mode" bei Software (egal ob Web oder Desktop)?

    • Kanashius
    • 13. März 2025 um 23:14
    Zitat

    Das Problem beim Dark Mode ist nur, dass der Kontrast fehlt und man die Ränder der Fenster nicht anhieb sieht, wenn sie übereinander liegen.

    Naja, das Problem liegt aber meiner Meinung nach aber daran, dass Windows lange keinen Darkmode hatte und es meines Wissens auch jetzt noch nicht so einfach möglich ist. Dazu kommt, dass GUIs in Win10/11 keine Rahmen mehr haben, sondern nurnoch einen leichten Schatten, der halt im Darkmode nicht ins Gewicht fällt.
    Viele nutzen deshalb schon lange nicht mehr die Standard Windows Fenster, sondern eigene (Firefox, Discord,...), die alle auch keinen Rahmen haben und wenn ich mich nicht täusche nichtmal einen Schatten.

    Es ist etwas schade, aber ich denke das ist einfach dem geschuldet, dass dark mode am Anfang nicht bedacht wurde (gab es noch nicht wirklich) und die Umsetzung immernoch nicht ausgereift und schon garnicht einheitlich ist. Deshalb entstehen dann solche Probleme.

    Beispiel:

    Spoiler anzeigen

    Wobei das im Explorer tatsächlich interessant gelöst wurde, indem die Titlebar oben nur beim aktiven Fenster dunkel ist und sonst grau. Das macht die Unterscheidung deutlich leichter. Außerdem haben die Explorer-Fenster auch einen sehr hellen Pixel drumherum, was deutlich beim erkennen hilft, wenn man mehrere übereinander hat. Das fehlt bei den "custom" Fenstern.

    Funfact: Ich hab gerade 3 (normal 4) Bildschirme. Ich schiebe extra leere Firefox Fenster auf die extra Bildschirme, wenn ich sie ne Zeit lang nicht benutze und dort was helles (ohne darkmode) angezeigt wird, damit es micht nicht so blendet :D (Ich mach sie nicht aus, weil ich oft "mal kurz" dann trotzdem was drüberschiebe oder so)

  • GUIRegisterMsg($WM_DRAWITEM, ...) Problem mit Map

    • Kanashius
    • 2. März 2025 um 23:21

    Ja, weil in seinem Beispiel die ComboBox (für alle Einträge) ausgelesen wird.

    Zitat

    Eigentlich könnte ich statt GUICtrlRead($cCombo) auf das funktionsintern gelesene $sText zugreifen. Hatte das aber mal testweise geändert, um es als Fehlerquelle auszuschließen.

    Wenn man das also mit $sText ersetzt sieht es so aus:

    AutoIt
    If MapExists($mUnit, $sText) And $mUnit[$sText]['access'] = 0 Then $clrForeground = 0x0000FF

    Und das funktioniert bei mir einwandfrei. Es sind Einträge in der Liste Rot und wenn man die auswählt ist auch die Farbe in dem ComboFeld richtig.

    Wenn ich mir $sText ausgeben lasse ist es halt manchmal ein leerer String und in so einem Fall existiert $mUnit[$sText] nunmal nicht und wenn man dann damit auf etwas zugreifen will schlägt das mit der Fehlermeldung fehl.
    Ich hab mir mit _ToStringC($mUnit) (_toString für alle (AutoIt-) Objekte (und mehr) sowie eine Methode zum Errorhandling) das ganze auch ausgeben lassen und die Map war immer komplett definiert.

    Win10, AutoIt 3.3.16.1

Spenden

Jeder Euro hilft uns, Euch zu helfen.

Download

AutoIt Tutorial
AutoIt Buch
Onlinehilfe
AutoIt Entwickler
  1. Datenschutzerklärung
  2. Impressum
  3. Shoutbox-Archiv
Community-Software: WoltLab Suite™