Morthawt Posted September 5, 2011 Share Posted September 5, 2011 (edited) I am trying to make a program to generate a 26x26 grid with each row containing the complete alphabet with randomized case where when you look at the columns they are also a complete alphabet that is multi case. All of which must not repeat any letters regardless of the case. I have tried numerous methods from generating 26 rows and then trying to remake a part of a row based on a detected duplicate letter in a column to what I am doing now which is trying to do it as I am making the row data so the rows get created to where each column is being built from the row data and is made from scratch to not have any duplicate letters etc. I am no autoit expert but I think my idea of checking the column data for the row the letter I am generating sits on for dupes and replacing the letter if it is detected should work flawlessly. But then again all my other concepts should have worked too. I have added a line to generate a msg box with the row data upon a row completion. The problem is it only gets to a certain line and then just stops.. maybe it will hit line 4 or 7 or something and then the program just is still running and does not generate anything else. Can someone have a look over my code and see what you think? expandcollapse popupGlobal $row[30] Global $col[30] Global $pool = '' Global $dupesexist = 0 $dedupedone = 0 $undupecol = 0 $pool = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM' $available = 0 $col2fix = 0 Global $deduped = 0 GenerateAllRows() ;~ Fakedata() DedupeAllCols() Func Fakedata() $row[1] = 'wZdkTpoLmFANcuGvbjRHsxeIqY' $row[2] = 'iDsubeklTQnYMWRpjZoxGvfahc' $row[3] = 'okAYlmxcQTdngbVRjhPfWziESu' $row[4] = 'NXqKUwMJTyOpBHVcAIfsLDzger' $row[5] = 'fNiwytbeHgqDZUOjkpSRVAxcLM' $row[6] = 'mQBNOZueXiATdSclgfHKRPYVwJ' $row[7] = 'cYITaNEgxUvqwobRsLjMKFPhzD' $row[8] = 'ejsVoNIxDAmyhTUqfCzWPBrLGk' $row[9] = 'DYteUwispZXMcONqrGKVJLabFH' $row[10] = 'lPRUMfIKtsZjVXcGHdYNOEqWBA' $row[11] = 'yAGPXesBDTLvFjNrMKQzCIHUoW' $row[12] = 'JvRyBqZnOFxEhPusmcAlTwgdki' $row[13] = 'boRwyZUJntakPXsgcLVeIHDqMF' $row[14] = 'ZhPUiBXwgKjmSVfcOELYArntDq' $row[15] = 'pXESdnuQrkcilGwHZABofmVJYT' $row[16] = 'xHeriFtuvmqwlSPkybdJzgcoaN' $row[17] = 'UWPVGMryOkfzEDQaIsnchjBxTL' $row[18] = 'SicmoBzdWJRqHnALfeUGyktpxv' $row[19] = 'kYxeFAMICLDHsjQRWBgTnUoZvP' $row[20] = 'VrfCKoWHIaZgNDbUjTxQmyLSPE' $row[21] = 'aKuwrotlEXDhszmYPVCibQJFnG' $row[22] = 'gLYnzmrxcQBjAVsHfdwPetukio' $row[23] = 'qgadUOhFPiNmtkLJVYebXSwrcZ' $row[24] = 'hLyzTSVoQGxpfwEAIJmDUcKnRb' $row[25] = 'tQKrwCVayGphenLFbZIUdOSmjX' $row[26] = 'RwCZBOVFehgdXKJipLtAQnMYuS' WriteRows('original') EndFunc ;==>Fakedata Func DedupeAllCols() Global $deduped = 0 While $deduped <> 26 $deduped = $deduped + 1 ;~ MsgBox(0, 0, 'De-duping now') DupeFixer($deduped) ;~ Sleep(100) ;~ WriteRows('result') ;~ MsgBox(0, 0, 'Done with row ' & $deduped) If $deduped = 26 Then ExitLoop WEnd WriteRows('result') EndFunc ;==>DedupeAllCols Func GenerateAllRows() For $currentrow = 1 To 26 GenerateRow($currentrow) Next WriteRows('original') GenerateCols() EndFunc ;==>GenerateAllRows Func GenerateRow($rowgen) $count = 0 $available = $pool $row[$rowgen] = '' $dupedetected = 0 If $row[1] = '' Then For $count = 1 To 26 Step 1 $availablelength = StringLen($available) $char = Random(1, $availablelength, 1) $actualchar = StringMid($available, $char, 1) $row[$rowgen] = $row[$rowgen] & StringMid($available, $char, 1) $available = StringReplace($available, $actualchar, '') Next Else For $count = 1 To 26 Step 1 GenerateCols() $availablelength = StringLen($available) $char = Random(1, $availablelength, 1) $actualchar = StringMid($available, $char, 1) If StringInStr($col[$count], $actualchar) <> 0 Then While 1 $char = Random(1, $availablelength, 1) $actualchar = StringMid($available, $char, 1) If StringInStr($col[$count], $actualchar) = 0 Then ExitLoop WEnd EndIf $row[$rowgen] = $row[$rowgen] & StringMid($available, $char, 1) $available = StringReplace($available, $actualchar, '') If StringLen($row[$rowgen]) = 26 Then MsgBox(0,$rowgen ,$row[$rowgen]) Next EndIf EndFunc ;==>GenerateRow Func WriteRows($type) If $type = 'original' Then FileDelete(@DesktopDir & '\original.txt') $writecount = 0 For $writecount = 1 To 26 FileWrite(@DesktopDir & '\original.txt', $row[$writecount] & @CRLF) Next Else FileDelete(@DesktopDir & '\result.txt') $writecount = 0 For $writecount = 1 To 26 FileWrite(@DesktopDir & '\result.txt', $row[$writecount] & @CRLF) Next EndIf EndFunc ;==>WriteRows Func GenerateCols() $c = 1 $r = 1 For $pre = 1 To 26 Step 1 $col[$pre] = '' Next While $c <> 27 For $r = 1 To 26 Step 1 $col[$c] = $col[$c] & StringMid($row[$r], $c, 1) Next $c = $c + 1 If $c = 27 Then ExitLoop WEnd EndFunc ;==>GenerateCols Func Dupechecker($checkcolfordupes) GenerateCols() $isthisadupe = 0 For $count = 1 To 26 $chartocheck = StringMid($col[$checkcolfordupes], $count, 1) $isthisadupe = $isthisadupe + StringInStr($col[$checkcolfordupes], $chartocheck, 0, 2) If $isthisadupe > 0 Then $dupesexist = 1 Next EndFunc ;==>Dupechecker Func DupeFixer($undupecol) $isthisadupe = 0 $dupesexist = 0 GenerateCols() For $count = 1 To 26 $chartocheck = StringMid($col[$undupecol], $count, 1) $isthisadupe = StringInStr($col[$undupecol], $chartocheck, 0, 2) ;~ MsgBox(0, 'Length: ' & StringLen($col[$undupecol]), $isthisadupe) If $isthisadupe > 0 Then $dupecase = StringMid($col[$undupecol], $isthisadupe, 1) $row[$isthisadupe] = StringReplace($row[$isthisadupe], $chartocheck, '') & $dupecase GenerateCols() ;~ $count = $count - 1 EndIf Next EndFunc ;==>DupeFixer Also if you know of a better more elegant method of generating this kind of grid please feel free to share how. All columns and rows must contain every letter of the alphabet and be random case letters, no duped letters. Edited September 5, 2011 by Morthawt Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
sleepydvdr Posted September 5, 2011 Share Posted September 5, 2011 (edited) I'm sure there's a better way, but here's what I came up with: #include <array.au3> ;ASCII Capital letters: 65-90; lowercase letters: 97-122 Dim $used[26] $i = 0 Do $var = Random(65, 90, 1) ; Random capital letters only _ArraySearch($used, $var) ; Only unique numbers If @error Then $used[$i] = $var $i += 1 EndIf Until $i = 26 Dim $charArray[26] ; Convert numbers to characters For $i = 0 to 25 Step 1 $capLow = Random(0, 1, 1) ; This section selects randomly between caps and lowercase If $capLow = 0 Then $charArray[$i] = Chr($used[$i]) Else $charArray[$i] = Chr($used[$i] + 32) EndIf Next _ArrayDisplay($charArray) ; Displays output as an array $string = _ArrayToString($charArray, "") MsgBox(0, "", $string) ; Displays output as a string Edited September 5, 2011 by sleepydvdr #include <ByteMe.au3> Link to comment Share on other sites More sharing options...
Morthawt Posted September 5, 2011 Author Share Posted September 5, 2011 I am confused how I would use that though. What I need to do is generate the first row of random case alphabet (which is easy) and then starting from the second line I need to check the character generated with all the characters above it to make sure it does not appear already and if it does appear then to select a different letter so that duplicate letter can be used further in the row where it will not have a dupe problem with any other letters above in a column. Everything I try keeps failing. The program will just sit there forever. Here is what I am working on right now: expandcollapse popupGlobal $row[28] Global $col[28] $pool = 'QWERTYUIOP' $available = $pool $size = StringLen($pool) $size1 = $size + 1 $r = 1 While $r <> $size1 $available = $pool For $c = 1 To $size Step 1 $length = StringLen($available) $charpos = Random(1, $length, 1) $actualchar = StringMid($available, $charpos, 1) $dupe = StringInStr($col[$c], $actualchar) If $r <> $size Then If StringRegExp($col[$c], '(?i)[' & $actualchar & ']') = 1 Then While 1 ;~ MsgBox(0,'',StringRegExp($col[$c], '(?i)[' & $actualchar & ']')) ;~ MsgBox(0,0,$actualchar) ;~ $length = StringLen($available) SRandom(Random()) $charpos = Random(1, $length, 1) $actualchar = StringMid($available, $charpos, 1) MsgBox(0,$r,$col[$c] & ' ' & $actualchar & '-- ' & $available) If StringRegExp($col[$c], '(?i)[' & $actualchar & ']') = 0 Then ExitLoop WEnd EndIf EndIf If $length = 1 Then $actualchar = StringMid($available, 1, 1) $row[$r] = $row[$r] & $actualchar $col[$c] = $col[$c] & $actualchar $available = StringReplace($available, $actualchar, '') Next $r = $r + 1 WEnd FileDelete(@DesktopDir & '\result.txt') For $w = 1 To 6 Step 1 FileWrite(@DesktopDir & '\result.txt', $row[$w] & @CRLF) Next ;~ MsgBox(0, 0, $col[6]) I have no idea what is going on. Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
sleepydvdr Posted September 5, 2011 Share Posted September 5, 2011 So basically, you are making a crossword puzzle kind of thing and you want every row and every column to be random. If that's what you are trying to do, I think you will run in to a problem with repetition. You can do a completely random horizontal row and random vertical column, but then you will be limited in what fills the rest of the space. I think it would have to be a diagonal repetitive pattern to fulfill your needs. If you told me what this is for, it might help me understand. #include <ByteMe.au3> Link to comment Share on other sites More sharing options...
Morthawt Posted September 5, 2011 Author Share Posted September 5, 2011 I am trying to make a Latin square I think they are called, as seen here: https://www.grc.com/OffTheGrid.htm It is used to make secure passwords, the requirement being that when you generate the characters that the rows and columns all contain the whole alphabet and there are no repetitive letters. It is not that complicated and I do not know why I am having issues. I have come up with at least 2 different ways that should work. Typically they work up to a few small columns and then go into an infinite loop or something. Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
sleepydvdr Posted September 5, 2011 Share Posted September 5, 2011 This is not perfect, but the best I can come up with so far. Maybe it will help you with some ideas: expandcollapse popup#include <array.au3> ;ASCII Capital letters: 65-90; lowercase letters: 97-122 Dim $tempArray[26] Dim $array[26][26] For $h = 0 to 25 step 1 _GenerateRandom() For $i = 0 To 25 Step 1 $array[$h][$i] = $tempArray[$i] Next Next _UniqueCheck() _ArrayDisplay($array) Func _GenerateRandom() For $j = 0 to 25 Step 1 $rand = Random(65, 90, 1) $tempArray[$j] = $rand _ArraySearch($tempArray, $rand) ; Only unique numbers If @error Then $tempArray[$i] = $rand $j += 1 EndIf Next For $i = 0 to 25 Step 1 $capLow = Random(0, 1, 1) ; This section selects randomly between caps and lowercase If $capLow = 0 Then $tempArray[$i] = Chr($tempArray[$i]) Else $tempArray[$i] = Chr($tempArray[$i] + 32) EndIf Next EndFunc Func _UniqueCheck() If _ArrayUnique($array, 0) <> 0 Then For $h = 0 to 25 step 1 _GenerateRandom() For $i = 0 To 25 Step 1 $array[$h][$i] = $tempArray[$i] Next Next EndIf If _ArrayUnique($array, 1) <> 0 Then For $h = 0 to 25 step 1 _GenerateRandom() For $i = 0 To 25 Step 1 $array[$h][$i] = $tempArray[$i] Next Next EndIf EndFunc #include <ByteMe.au3> Link to comment Share on other sites More sharing options...
Malkey Posted September 5, 2011 Share Posted September 5, 2011 Here is a method of generating unique characters in each row and each column of an array. #include <array.au3> Local $str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" Local $aCharArray = StringSplit($str, "", 2) Local $iSize = UBound($aCharArray) ;_ArrayDisplay($aCharArray) Local $aArray[$iSize][$iSize] Local $sRow, $index = "|", $Rand ; Generate one random line of all characters. (The string to be rotated.) For $r = 0 To $iSize - 1 Do $Rand = $aCharArray[Random(0, ($iSize - 1), 1)] Until (StringInStr($sRow, $Rand, 1) = 0) $sRow &= $Rand Next $Rand = "" For $r = 0 To $iSize - 1 Do $Rand = Random(0, ($iSize - 1), 1) Until (StringInStr($index, "|" & $Rand & "|", 1) = 0) $index &= $Rand & "|" $sRow = StringTrimRight(StringRight($sRow, 1) & $sRow, 1) ; Rotate string by one character (last character moved to be first character). Local $temp = StringSplit($sRow, "", 2) For $c = 0 To UBound($temp) - 1 $aArray[$Rand][$c] = $temp[$c] ; Place the split rotated string randomly into one of the rows of an array. Next Next ;ConsoleWrite($index & @LF) _ArrayDisplay($aArray) Link to comment Share on other sites More sharing options...
Morthawt Posted September 5, 2011 Author Share Posted September 5, 2011 Here is a method of generating unique characters in each row and each column of an array. #include <array.au3> Local $str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" Local $aCharArray = StringSplit($str, "", 2) Local $iSize = UBound($aCharArray) ;_ArrayDisplay($aCharArray) Local $aArray[$iSize][$iSize] Local $sRow, $index = "|", $Rand ; Generate one random line of all characters. (The string to be rotated.) For $r = 0 To $iSize - 1 Do $Rand = $aCharArray[Random(0, ($iSize - 1), 1)] Until (StringInStr($sRow, $Rand, 1) = 0) $sRow &= $Rand Next $Rand = "" For $r = 0 To $iSize - 1 Do $Rand = Random(0, ($iSize - 1), 1) Until (StringInStr($index, "|" & $Rand & "|", 1) = 0) $index &= $Rand & "|" $sRow = StringTrimRight(StringRight($sRow, 1) & $sRow, 1) ; Rotate string by one character (last character moved to be first character). Local $temp = StringSplit($sRow, "", 2) For $c = 0 To UBound($temp) - 1 $aArray[$Rand][$c] = $temp[$c] ; Place the split rotated string randomly into one of the rows of an array. Next Next ;ConsoleWrite($index & @LF) _ArrayDisplay($aArray) Steve Gibson talked about this on the Securitynow pod cast and said while it will work, the level of entropy is not enough to have the maximum possible combinations. The best way is completely random with no "shifting" to get the unique result. Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
Morthawt Posted September 6, 2011 Author Share Posted September 6, 2011 Here is a visual representation of what and how I am trying to generate this grid: Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
Morthawt Posted September 6, 2011 Author Share Posted September 6, 2011 This code is completely rewritten and is as basic as I can make it. It works for a few rows and then just locks up and does no more. The script keeps running but does nothing: expandcollapse popup$pool = 'QWERTYUIOPASDFGHJKLZXCVBNM' $available = $pool Global $row[28] Global $col[28] Global $a Global $length Global $char Global $available FileDelete(@DesktopDir & '\result.txt') $r = 1 For $a = 1 To 26 Step 1 $length = StringLen($available) $random = Random(1, $length, 1) $char = StringMid($available, $random, 1) $row[$r] = $row[$r] & $char $col[$a] = $col[$a] & $char $available = StringReplace($available, $char, '') Next FileWrite(@DesktopDir & '\result.txt', $row[$r] & @CRLF) $r = $r + 1 While 1 $available = $pool For $a = 1 To 26 Step 1 $length = StringLen($available) While 1 $random = Random(1, $length, 1) $char = StringMid($available, $random, 1) If StringInStr($col[$a], $char) = 0 Then ExitLoop WEnd $row[$r] = $row[$r] & $char $col[$a] = $col[$a] & $char $available = StringReplace($available, $char, '') Next If $r = 26 Then ExitLoop FileWrite(@DesktopDir & '\result.txt', $row[$r] & @CRLF) $r = $r + 1 WEnd As I said, it is working and doing what it is supposed to do, only it does not keep doing it past 7 - 12 rows or so. Any ideas? Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
Morthawt Posted September 6, 2011 Author Share Posted September 6, 2011 So far I have it working but it is only getting to about row 19 before getting VERY slow indeed. Can you test this out (I added console writes so you can see the rows and it also saves to a file when each row is completed) and see if you can suggest some way to speed the process up? Thanks expandcollapse popupGlobal $data[27][27] Global $r Global $pool Global $available Global $colstring Global $rowstring Global $skipped FileDelete(@DesktopDir & '\result.txt') $pool = 'QWERTYUIOPASDFGHJKLZXCVBNM' GenerateAllRows() Func GenerateAllRows() For $g = 1 To 26 Step 1 GenerateRow($g) BuildRow($g) $count = $g If StringLen($g) = 1 Then $count = 0 & $g If $rowstring <> '' Then ConsoleWrite('Row: ' & $count & ' - ' & $rowstring & @CRLF) FileWrite(@DesktopDir & '\result.txt', $rowstring & @CRLF) Else While $rowstring = '' SRandom(Random(1, 9999999999, 1)) GenerateRow($g) BuildRow($g) WEnd FileWrite(@DesktopDir & '\result.txt', $rowstring & @CRLF) ConsoleWrite('Row: ' & $count & ' - ' & $rowstring & @CRLF) EndIf ;~ If $rowstring = '' Then ConsoleWrite('Skipped row: ' & $g & @CRLF) Next EndFunc ;==>GenerateAllRows Func GenerateRow($row) $available = $pool $try = 0 For $a = 1 To 26 Step 1 $length = StringLen($available) $random = Random(1, $length, 1) $char = StringMid($available, $random, 1) If $length = 1 Then $char = $available BuildCol($a) While StringInStr($colstring, $char) <> 0 $random = Random(1, $length, 1) $char = StringMid($available, $random, 1) If $length = 1 Then $char = $available $try = $try + 1 If $try > 27 Then ResetRow($row) ExitLoop (2) EndIf WEnd $data[$row][$a] = $char $available = StringReplace($available, $char, '') Next EndFunc ;==>GenerateRow Func BuildCol($col) $colstring = '' For $a = 1 To 26 Step 1 $colstring = $colstring & $data[$a][$col] Next EndFunc ;==>BuildCol Func BuildRow($row) $rowstring = '' For $a = 1 To 26 Step 1 $rowstring = $rowstring & $data[$row][$a] Next EndFunc ;==>BuildRow Func ResetRow($row) For $a = 1 To 26 Step 1 $data[$row][$a] = '' Next EndFunc ;==>ResetRow Func ListSkippedLine($skipcheck) BuildRow($skipcheck) If $rowstring = '' Then $skipped = $skipcheck EndIf EndFunc ;==>ListSkippedLine Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
BrewManNH Posted September 6, 2011 Share Posted September 6, 2011 I changed the the line If $try > 27 Then to If $try > 1000 Then and I was able to complete the grid in about 20 seconds on my laptop. I think the reason it was taking so long before is because you're resetting the row data so often that it has less chance of completing in a timely fashion. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator Link to comment Share on other sites More sharing options...
Morthawt Posted September 6, 2011 Author Share Posted September 6, 2011 Funny you mention that I have been playing with that code and while it does help, it is random. Sometimes its very quick and other times it takes longer. I am not sure why. Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
BrewManNH Posted September 6, 2011 Share Posted September 6, 2011 With the default of 27 as per your script, I completed 21 rows in about 15 minutes compared to all 26 in 30 seconds just by changing that one variable. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator Link to comment Share on other sites More sharing options...
Morthawt Posted September 6, 2011 Author Share Posted September 6, 2011 Yes, the only problem is it is supposed to take only 2 or 3 seconds. Check this page out and hit the "get it done" button https://www.grc.com/offthegrid.htm I need to generate it very quickly. The thing is if my letters that are left cannot be used because they all collide with the column, then I scratch that attempt and generate a whole new random line to replace it. That way I am starting that row from scratch if its "impossible" to solve. The issue is I cannot seem to get it to do this very very quickly. This source code shows you the data that is being generated to try and make a row. You will see it swap and change once it fails. I am trying to speed the process up but running into brick walls. I know its possible, I just am not sure how I am going to do this. expandcollapse popupGlobal $data[27][27] Global $r Global $pool Global $available Global $colstring Global $rowstring Global $skipped Global $backupavailable FileDelete(@DesktopDir & '\result.txt') $pool = 'QWERTYUIOPASDFGHJKLZXCVBNM' GenerateAllRows() Func GenerateAllRows() For $g = 1 To 26 Step 1 GenerateRow($g) BuildRow($g) $count = $g If StringLen($g) = 1 Then $count = 0 & $g If $rowstring <> '' Then ConsoleWrite('Row: ' & $count & ' - ' & $rowstring & @CRLF) FileWrite(@DesktopDir & '\result.txt', $rowstring & @CRLF) Else While $rowstring = '' SRandom(Random(1, 9999999999, 1)) GenerateRow($g) BuildRow($g) WEnd FileWrite(@DesktopDir & '\result.txt', $rowstring & @CRLF) ConsoleWrite('Row: ' & $count & ' - ' & $rowstring & @CRLF) EndIf ;~ If $rowstring = '' Then ConsoleWrite('Skipped row: ' & $g & @CRLF) Next EndFunc ;==>GenerateAllRows Func GenerateRow($row) $available = $pool $try = 0 $currentrow = '' $backupavailable = '' For $a = 1 To 26 Step 1 $length = StringLen($available) $random = Random(1, $length, 1) $char = StringMid($available, $random, 1) If $length = 1 Then $char = $available BuildCol($a) While StringInStr($colstring, $char) <> 0 $backupavailable = $available $length = StringLen($available) $random = Random(1, $length, 1) $char = StringMid($available, $random, 1) If $length = 1 Then $char = $available ;~ If StringInStr($colstring, $char) <> 0 Then $available = StringReplace($available, $char, '') $try = $try + 1 If $try > 1000 Then ResetRow($row) ExitLoop (2) EndIf WEnd ;~ $available = $backupavailable $data[$row][$a] = $char $currentrow = $currentrow & $char $available = StringReplace($available, $char, '') ConsoleWrite('Row ' & $row & ' Data so far: ' & $currentrow & @CRLF) Next EndFunc ;==>GenerateRow Func BuildCol($col) $colstring = '' For $a = 1 To 26 Step 1 $colstring = $colstring & $data[$a][$col] Next EndFunc ;==>BuildCol Func BuildRow($row) $rowstring = '' For $a = 1 To 26 Step 1 $rowstring = $rowstring & $data[$row][$a] Next EndFunc ;==>BuildRow Func ResetRow($row) For $a = 1 To 26 Step 1 $data[$row][$a] = '' Next EndFunc ;==>ResetRow Func ListSkippedLine($skipcheck) BuildRow($skipcheck) If $rowstring = '' Then $skipped = $skipcheck EndIf EndFunc ;==>ListSkippedLine I have gone from thinking its impossible, to generating ideas on how do to it. Disproving those ideas (eventually through debugging the code manually using console writes) and now I have it working and just need to improve the speed, to make it optimal. I am progressing, this seems to be my final battle right now. I am 90% sure the data in the rows is not duping when looked at as a column, so speed is the issue now. Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
Morthawt Posted September 6, 2011 Author Share Posted September 6, 2011 Upon using the code I pasted in my last message, I can see that when it ditches its attempt to solve the row and restart the row from scratch that it sometimes is using the same letters and thus partially making the same selections as it did on the previous attempts. If I can find a way to prevent it from trying the same combinations it would speed things up to being almost instant as I am looking for.. The question is how... Hmm Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
Morthawt Posted September 6, 2011 Author Share Posted September 6, 2011 (edited) I have made something that appears to still work ok and has a save as dialogue etc. I still cannot increase the speed though... expandcollapse popup#include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include <File.au3> Global $data[27][27] Global $r Global $Form1_1 Global $pool Global $available Global $colstring Global $rowstring Global $skipped Global $backupavailable Global $number Global $indicator Global $percent Local $drive Global $dupecount Local $dir Local $filename Global $file Local $ext FileDelete($file) $pool = 'QWERTYUIOPASDFGHJKLZXCVBNM' $file = FileSaveDialog('Save Latin Square', @DesktopDir, 'Text files (*.txt)', 16) _PathSplit($file, $drive, $dir, $filename, $ext) If $ext = '' Then $file = $file & '.txt' If FileExists($file) Then FileDelete($file) GenerateAllRows() ;~ CheckColForDupes(21) MsgBox(0,'Completed', 'Grid has been completed') Func GenerateAllRows() $number = 0 For $g = 1 To 26 Step 1 GenerateRow($g) $number = $number + 1 BuildRow($g) $count = $g If StringLen($g) = 1 Then $count = 0 & $g If $rowstring <> '' Then ConsoleWrite('Row: ' & $count & ' - ' & $rowstring & @CRLF) FileWrite($file, $rowstring & @CRLF) $percent = ($g / 26) * 100 Else While $rowstring = '' ;~ SRandom(Random(1, 9999999999, 1)) GenerateRow($g) $number = $number + 1 BuildRow($g) WEnd FileWrite($file, $rowstring & @CRLF) ConsoleWrite('Row: ' & $count & ' - ' & $rowstring & @CRLF) EndIf Next EndFunc ;==>GenerateAllRows Func GenerateRow($row) $available = $pool $try = 0 $currentrow = '' $backupavailable = '' For $a = 1 To 26 Step 1 $length = StringLen($available) $random = Random(1, $length, 1) $char = StringMid($available, $random, 1) If $length = 1 Then $char = $available BuildCol($a) While StringInStr($colstring, $char) <> 0 $backupavailable = $available $length = StringLen($available) $random = Random(1, $length, 1) $char = StringMid($available, $random, 1) If $length = 1 Then $char = $available $try = $try + 1 If $try > 1000 Then ResetRow($row) ExitLoop (2) EndIf WEnd $data[$row][$a] = $char $currentrow = $currentrow & $char $available = StringReplace($available, $char, '') $percent = Round(($row / 26) * 100, 0) ;~ ConsoleWrite('Row ' & $row & ' Data so far: ' & $currentrow & @CRLF) ;~ ConsoleWrite('Number of generated rows: ' & $number & @CRLF) If StringLen($currentrow) = 26 Then GUICtrlSetData($indicator, Round($percent, 0) & ' percent complete') Next EndFunc ;==>GenerateRow Func BuildCol($col) $colstring = '' For $a = 1 To 26 Step 1 $colstring = $colstring & $data[$a][$col] Next EndFunc ;==>BuildCol Func BuildRow($row) $rowstring = '' For $a = 1 To 26 Step 1 $rowstring = $rowstring & $data[$row][$a] Next EndFunc ;==>BuildRow Func CheckColForDupes($dupe) BuildCol($dupe) $dupecount = 0 For $d = 1 To 26 Step 1 $char = StringMid($colstring, $d, 1) If StringInStr($colstring, $char, 0, 2) <> 0 Then $dupecount = $dupecount + 1 Next EndFunc ;==>CheckColForDupes Func ResetRow($row) For $a = 1 To 26 Step 1 $data[$row][$a] = '' Next EndFunc ;==>ResetRow Func ListSkippedLine($skipcheck) BuildRow($skipcheck) If $rowstring = '' Then $skipped = $skipcheck EndIf EndFunc ;==>ListSkippedLine Any thoughts? Edited September 6, 2011 by Morthawt Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
BrewManNH Posted September 7, 2011 Share Posted September 7, 2011 I've been working at this for the last day now to see if I could make it any faster, unfortunately the speed of an interpreted language just isn't going to be very fast for something like this. expandcollapse popupGlobal $Timer = TimerInit() Global $Array[26][26], $ColumnData[26][26] Global $Pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" Global $FileName = @ScriptDir & "\LatinSquare.txt" _GenerateAllRows() Func _GenerateAllRows() Local $File = FileOpen($FileName, 2) For $iRow = 0 To 25 While Not _GenerateRow($iRow) ; If this returns false, then a row wasn't generated _Reset($iRow) ; clears the current row and column data, also reseed the RNG ;the following code chooses a random pattern for $Pool from the previously used patterns ;this helps generate new random patterns in combination with the reseed operation above ;so that hopefully it will finish faster $Pool = "" $Ran = Random(0, $iRow - 1, 1) For $Loop = 0 To 25 $Pool &= $Array[$Ran][$Loop] Next WEnd ConsoleWrite("Row # " & $iRow & @CRLF) ;the following writes the current line to a text file, the characters are delimited by the "|" character $Line = "" For $X = 0 To 25 $Line &= $Array[$iRow][$X] & "|" Next $Line = StringTrimRight($Line, 1) FileWriteLine($File, $Line) Next $Time = Round(TimerDiff($Timer) / 1000, 2) FileWriteLine($File, "Run time: " & $Time) ; writes the execution time to the text file FileClose($File) FileCopy($FileName, @ScriptDir & "\LatinSquare " & $Time & ".txt") EndFunc ;==>_GenerateAllRows Func _GenerateRow($RowNum) ;Generate a row Local $Loop = 0, $Length, $Random, $Char, $Available = $Pool For $I = 0 To 25 $Length = StringLen($Available) ; as letters are placed, the length gets shorter by one If $Length > 1 Then $Random = Random(1, $Length, 1) $Char = StringMid($Available, $Random, 1) Else ; if $Available is down to the last character, then set $char to that character rather than trying to use Random $Char = $Available EndIf While _CheckCol($Char, $I) ; checks to make sure that character hasn't been used in that column already, if it has, run the following code. $Random = Random(1, $Length, 1) $Char = StringMid($Available, $Random, 1) $Loop += 1 If $Loop > 100 Then Return False WEnd $Loop = 0 $Array[$RowNum][$I] = $Char $ColumnData[$RowNum][$I] = $Char $Available = StringReplace($Available, $Char, '') Next Return True EndFunc ;==>_GenerateRow Func _CheckCol($Letter, $Column) For $I = 0 To 25 If $ColumnData[$I][$Column] = $Letter Then Return SetError(4, 0, True) EndIf Next Return False EndFunc ;==>_CheckCol Func _Reset($Row) $Seed = Random(1, 2147483647, 1) SRandom($Seed) For $I = 0 To 25 $Array[$Row][$I] = "" $ColumnData[$Row][$I] = "" Next EndFunc ;==>_Reset The problem with this code is that it will sometimes take as little as 2 seconds and sometimes takes over 2 minutes. It creates a text file called LatinSquare.txt, and then copies it to a new file called LatinSquare<run time>.txt so that if it takes 3.44 seconds to run, the copied file is named "LatinSquare 3.44.txt". I've tried to make the randomness a little bit better by reseeding the RNG and then choosing a previous row's characters for the $Pool variable so that the character layout isn't the same one every time. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator Link to comment Share on other sites More sharing options...
Morthawt Posted September 9, 2011 Author Share Posted September 9, 2011 I've been working at this for the last day now to see if I could make it any faster, unfortunately the speed of an interpreted language just isn't going to be very fast for something like this. expandcollapse popupGlobal $Timer = TimerInit() Global $Array[26][26], $ColumnData[26][26] Global $Pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" Global $FileName = @ScriptDir & "\LatinSquare.txt" _GenerateAllRows() Func _GenerateAllRows() Local $File = FileOpen($FileName, 2) For $iRow = 0 To 25 While Not _GenerateRow($iRow) ; If this returns false, then a row wasn't generated _Reset($iRow) ; clears the current row and column data, also reseed the RNG ;the following code chooses a random pattern for $Pool from the previously used patterns ;this helps generate new random patterns in combination with the reseed operation above ;so that hopefully it will finish faster $Pool = "" $Ran = Random(0, $iRow - 1, 1) For $Loop = 0 To 25 $Pool &= $Array[$Ran][$Loop] Next WEnd ConsoleWrite("Row # " & $iRow & @CRLF) ;the following writes the current line to a text file, the characters are delimited by the "|" character $Line = "" For $X = 0 To 25 $Line &= $Array[$iRow][$X] & "|" Next $Line = StringTrimRight($Line, 1) FileWriteLine($File, $Line) Next $Time = Round(TimerDiff($Timer) / 1000, 2) FileWriteLine($File, "Run time: " & $Time) ; writes the execution time to the text file FileClose($File) FileCopy($FileName, @ScriptDir & "\LatinSquare " & $Time & ".txt") EndFunc ;==>_GenerateAllRows Func _GenerateRow($RowNum) ;Generate a row Local $Loop = 0, $Length, $Random, $Char, $Available = $Pool For $I = 0 To 25 $Length = StringLen($Available) ; as letters are placed, the length gets shorter by one If $Length > 1 Then $Random = Random(1, $Length, 1) $Char = StringMid($Available, $Random, 1) Else ; if $Available is down to the last character, then set $char to that character rather than trying to use Random $Char = $Available EndIf While _CheckCol($Char, $I) ; checks to make sure that character hasn't been used in that column already, if it has, run the following code. $Random = Random(1, $Length, 1) $Char = StringMid($Available, $Random, 1) $Loop += 1 If $Loop > 100 Then Return False WEnd $Loop = 0 $Array[$RowNum][$I] = $Char $ColumnData[$RowNum][$I] = $Char $Available = StringReplace($Available, $Char, '') Next Return True EndFunc ;==>_GenerateRow Func _CheckCol($Letter, $Column) For $I = 0 To 25 If $ColumnData[$I][$Column] = $Letter Then Return SetError(4, 0, True) EndIf Next Return False EndFunc ;==>_CheckCol Func _Reset($Row) $Seed = Random(1, 2147483647, 1) SRandom($Seed) For $I = 0 To 25 $Array[$Row][$I] = "" $ColumnData[$Row][$I] = "" Next EndFunc ;==>_Reset The problem with this code is that it will sometimes take as little as 2 seconds and sometimes takes over 2 minutes. It creates a text file called LatinSquare.txt, and then copies it to a new file called LatinSquare<run time>.txt so that if it takes 3.44 seconds to run, the copied file is named "LatinSquare 3.44.txt". I've tried to make the randomness a little bit better by reseeding the RNG and then choosing a previous row's characters for the $Pool variable so that the character layout isn't the same one every time. I tried reseeding too (not sure if I left it commented out or took it out though). I do not understand the varying delays in completion time. Whether it is your code or mine, sometimes it is fast and others it is slow. Steve Gibson's one uses javascript, so I am not sure how that is so different from Autoit script in terms of execution times etc. Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
BrewManNH Posted September 9, 2011 Share Posted September 9, 2011 Have you tried his site and used the radio button for "See how it works" or however it is titled? It can take a VERY long time to create the grid when you're watching it work, which leads me to believe that it might be creating random grids behind the scenes and only displaying the completed ones. I have elaborated on this idea to create a fully functioning password creator using Latin Squares. I have noticed a flaw in using them though, if there are repeated letters in the input string, the result is a little confusing. Although if you follow the logic of the script (which I will post later when I'm at the computer it's stored on), you can see how it is getting the output that it generates for the password. At least it's consistently getting the same password every time, so the logic isn't at fault, just my implementation of it. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now