BitByteBit Posted June 3, 2010 Share Posted June 3, 2010 (edited) Somebody set me a puzzle. I was to work out the values of each letter in this equation: "Send + More = Money".I sat down with a pen and paper and worked it out, but then I wanted to write a script that could work it out through brute force and or guessing.This is what I came up with:expandcollapse popup#cs SEND +MORE MONEY #ce Global $Array[2][10] = [["0", "1", "X", "X", "X", "X", "X", "X", "X", "X"],[0]] $Array[1][0] = 0 Global $T1, $Send, $More, $Money, $R, $Last $Solved = False $C = 1 $T2 = TimerInit() Do $E = _RandomizeNumbers() $Send = _RandomizeNumbers() & $E & _RandomizeNumbers() & _RandomizeNumbers() $More = $Array[0][1] & $Array[0][0] & _RandomizeNumbers() & $E If $Send + $More = StringLeft($More, 2) & StringMid($Send, 3, 1) & $E & 2 Then ;Dirty, dirty cheater... $Solved = True ExitLoop EndIf $C += 1 Global $Array[2][10] = [["0", "1", "X", "X", "X", "X", "X", "X", "X", "X"],[0]] Until $Solved = True $T2 = TimerDiff($T2) ConsoleWrite(@CRLF & "Time taken: " & Round($T2 / 1000, 2) & @CRLF & "Calculations:" & $C & @CRLF & "Send: " & $Send & @CRLF & "More: " & $More & @CRLF & "Money: " & $Send + $More & @CRLF) Exit Func _RandomizeNumbers() ;Purpose, to generate a unique random number. $R = _Random() If $Array[0][$R] = "X" Then $Array[0][$R] = $R Else _RandomizeNumbers() EndIf Return $R EndFunc ;==>_RandomizeNumbers Func _Random() Return Random(0, 9, 1) EndFunc ;==>_Random #cs Lots of boring, useless code... $T1 = Random(1, 9, 1) ;E $Send = Random(1, 9, 1) & $T1 & Random(1, 9, 1) & Random(1, 9, 1) $More = 1 & Random(0, 9, 1) & Random(1, 9, 1) & $T1 $Y = StringMid($Send,4,1) + StringMid($More,4,1) ;If $Send + $More = StringLeft($More,2) & StringMid($Send,3,1) & Random(1, 9, 1)& $T1 & StringMid($Send,4,1) + StringMid($More,4,1) ;$C += 1 $D += 1 If TimerDiff($T) < 5000 Then If TimerDiff($T) > 1000 Then ConsoleWrite("CPS: " & $D & @CRLF) ;ConsoleWrite("TCE: " & $C & @CRLF) $D = 0 ;$T = TimerInit() EndIf EndIf Func _RandomizeNumbers() Global $T1 = Random(1, 9, 1) ;E Global $Send = Random(1, 9, 1) & $T1 & Random(1, 9, 1) & Random(1, 9, 1) Global $More = Random(1, 9, 1) & Random(1, 9, 1) & Random(1, 9, 1) & $T1 Global $Money = $Send + $More EndFunc ;==>_RandomizeNumbers Func _RandomizeNumbers() If $Array[1][0] = 9 Then Global $Array [2][10] =[[0,0], [1,2,0,0,0,0,0]] $R = Random(0,9,1) If not $Array[0][$R] = $R Then $Array[0][$R] = $R $Array[1][0] +=1 Return $R Else _RandomizeNumbers() EndIf EndFunc Func _RandomizeNumbers() If $Array[1][0] = 10 Then Global $Array[2][10] ;_ArrayDisplay($Array) $R = Random(0, 9, 1) If Not $Array[0][$R] = $R Then ToolTip("Array:" & $R) $Array[0][$R] = $R $Array[1][0] += 1 Return $R Else For $X = 0 To 9 If $Array[0][$X] = "" Then ToolTip("Array:2" & $X) $Array[0][$X] = $X $Array[1][0] += 1 Return $X EndIf Next EndIf _ArrayDisplay($Array) EndFunc ;==>_RandomizeNumbers M = 1 O = 0 N = 6 E = 5 Y = 2 D = 7, R = 8, and S = 9. Func _RandomizeNumbers() If $Array[1][0] = 10 Then Global $Array[2][10] = [["", "", "", "", "", "", "", "", ""],[0]] $R = Random(0, 9, 1) If Not $Array[0][$R] = $R and $Array[0][$R] = "" Then $Array[0][$R] = $R $Array[1][0] += 1 ConsoleWrite("New Random Number: " & $Array[0][$R]&@CRLF) Else ConsoleWrite("Old Random Number: " & $R&@CRLF) For $X = 0 To 9 If $Array[0][$X] = "" Then $Array[0][$X] = $X ConsoleWrite("New Random Number: " & $Array[0][$R]&@CRLF) $Array[1][0] += 1 $R = $X ExitLoop EndIf Next EndIf ;_ArrayDisplay($Array) Return $R EndFunc ;==>_RandomizeNumbers If StringLen(StringMid($Send, 4, 1) + StringMid($More, 4, 1)) > 1 Then $Y = StringTrimLeft(StringMid($Send, 4, 1) + StringMid($More, 4, 1), 1) Else $Y = StringMid($Send, 4, 1) + StringMid($More, 4, 1) EndIf #ceI'm really unhappy with it, I cheat, and it's not brute force. Can anybody push me in the right direction?Wikipedia say that I could use mod to help me work it out, but my maths isn't so strong .http://en.wikipedia.org/wiki/Verbal_arithmeticHelp me Obi Wan Kenobi,You're my only hope. Edited June 3, 2010 by BitByteBit Link to comment Share on other sites More sharing options...
muhmuuh Posted June 3, 2010 Share Posted June 3, 2010 Hi! You can bruteforce all combinations for Send and More and than see if the result could match Money. To bruteforce Send and Money you will have to generate all possible numbers for s,e,n,d,m,o,y; which is less than 10^7 combinations. Example for $s=0 to 9 for $e=0 to 9 for $n=0 to 9 ... for $y=0 to 9 $send=$s*1000+$e*100+$n*10+$d same for $more $money=$send+$more and you check if the numbers for m,o,n,e match with those you've always generated and check if $y is different from all other letters. also in the loops you need to make sure that the letters are different. Good luck! I ran. I ran until my muscles burned and my veins pumped battery acid. Then I ran some more. Link to comment Share on other sites More sharing options...
Tvern Posted June 4, 2010 Share Posted June 4, 2010 (edited) For a nice challenge you can make a script that would work for other challenges like this. I've started making one myself Edit: And came up with this. expandcollapse popup#include <Array.au3> $script = _BuildScript("Send","More","Money") $array = _RunScript($script) _ArrayDisplay($array) ; #FUNCTION# ==================================================================================================================== ; Name...........: _BuildScript ; Description ...: Returns a script to evaluate possible values of the letters in 3 given strings ; Syntax.........: _BuildScript($sWord1, $sWord2, $sResult[, $nBase = 10[, $bUnique = True[, $canbe0 = False]]]) ; Parameters ....: $sWord1 - The first string to evaluate ; $sWord2 - The second string to evaluate ; $sResult - The sum of $sWord1 and $sWord2 ; $nBase - [optional] the system to use. (Default is 10, for decimal) !!!!not working yet!!!! ; $bUnique - [optional] Flag to indicate if numbers represent an unique number, or if doubles are allowed (Default is True, for unique numbers) ; $canbe0 - [optional] Flag to indicate if the first letter of each string can be 0 (Default is False, the fist letter has to be at least 1) ; Return values .: Success - Returns working script ; Failure - Not so lucky ; Author ........: Tom ; Remarks .......: Proper errorchecking is not on the ToDo list ; Related .......: _RunScript($script) ; =============================================================================================================================== Func _BuildScript($sWord1, $sWord2, $sResult, $nBase = 10, $bUnique = True, $canbe0 = False) If $nBase <> 10 Then MsgBox(0,"error","base" & $nBase & " is not yet implemented.") Return EndIf Local $script, $tabsstring, $ScriptEnd Local $nWord1, $nWord2, $nResult $sWord1 = StringLower($sWord1) $sWord2 = StringLower($sWord2) $sResult = StringLower($sResult) $aLetters = _UniqueLetters($sWord1&$sWord2&$sResult) ;create the embedded For...To...Next loops $script = "Local $Return, $Word1, $Word2, $Result" & @CRLF For $i = 1 To $aLetters[0] $tabsstring = "" For $i0 = 2 To $i ;proper indentation because it's nice $tabsstring &= @TAB Next $script &= $tabsstring ;conditional based on the value of $canbe0 Switch $aLetters[$i] Case $canbe0 $script &= "For $" & $aLetters[$i] & " = 0 To " & $nBase-1 & @CRLF ;first letter is allowed to be 0 Case StringLeft($sWord1,1), StringLeft($sWord2,1), StringLeft($sResult,1) $script &= "For $" & $aLetters[$i] & " = 1 To " & $nBase-1 & @CRLF ;this is a first letter and not allowed to be 0 Case Else $script &= "For $" & $aLetters[$i] & " = 0 To " & $nBase-1 & @CRLF ;this is not a first letter EndSwitch ;conditional based on the value of $bUnique ;create a switch statement to "continueloop" if another letter already has this value. If $bUnique And ($i > 1) Then $script &= $tabsstring & @TAB $script &= "Switch $" & $aLetters[$i] & @CRLF $script &= $tabsstring & @TAB & @TAB $script &= "Case " For $i1 = 1 To $i-1 $script &= "$" & $aLetters[$i1] If $i1 < $i-1 Then $script &= ", " Else $script &= @CRLF EndIf Next $script &= $tabsstring & @TAB & @TAB & @TAB $script &= "ContinueLoop" & @CRLF $script &= $tabsstring & @TAB $script &= "EndSwitch" & @CRLF EndIf ;this creates a properly tabbed end of the script to be added when the script is complete. $ScriptEnd = $tabsstring & "Next" & @CRLF & $ScriptEnd Next ;This is the code that checks if $Word1 + $Word2 = $Result ;Convert Words to Numbers ;faster then Number($w&$o&$r&$d) For $i = 1 To StringLen($sWord1) $nWord1 &= "$" & StringMid($sWord1,$i,1) & "*" & 10^(StringLen($sWord1)-($i*1)) If $i < StringLen($sWord1) Then $nWord1 &= "+" Next $script &= $tabsstring & @TAB $script &= "$Word1 = " & $nWord1 & @CRLF For $i = 1 To StringLen($sWord2) $nWord2 &= "$" & StringMid($sWord2,$i,1) & "*" & 10^(StringLen($sWord2)-($i*1)) If $i < StringLen($sWord2) Then $nWord2 &= "+" Next $script &= $tabsstring & @TAB $script &= "$Word2 = " & $nWord2 & @CRLF For $i = 1 To StringLen($sResult) $nResult &= "$" & StringMid($sResult,$i,1) & "*" & 10^(StringLen($sResult)-($i*1)) If $i < StringLen($sResult) Then $nResult &= "+" Next $script &= $tabsstring & @TAB $script &= "$Result = " & $nResult & @CRLF ;Compare Numbers $script &= $tabsstring & @TAB $script &= "If $Word1+$Word2 = $Result Then" & @CRLF $script &= $tabsstring & @TAB & @TAB $script &= "$Return &= $Word1 & '+' & $Word2 & '=' & $Result & ','" & @CRLF $script &= $tabsstring & @TAB $script &= "Endif" & @CRLF $script &= $ScriptEnd $script &= "ConsoleWrite($Return)" Return $script EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: _UniqueLetters ; Description ...: Returns an array of unique letters found in a string ; Syntax.........: _UniqueLetters($string) ; Parameters ....: $string - The string to get the unique letters from ; Return values .: Success - A 1-based array of letters with $array[0] containging the count ; Author ........: Tom ; Remarks .......: This function is used internally by _BuildScript. ; Related .......: _BuildScript ; =============================================================================================================================== Func _UniqueLetters($string) Local $newstring, $letter For $i = 0 To StringLen($string) $letter = StringMid($string,$i,1) If StringInStr($newstring,$letter) Then ContinueLoop $newstring &= $letter Next Return StringSplit($newstring,"") EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: _RunScript ; Description ...: Runs a script created by _BuildScript() and returns the output as an array ; Syntax.........: _RunScript($script) ; Parameters ....: $script - The script to execute ; Return values .: Success - 1-based array with results ; Failure - Not so lucky ; Author ........: Tom ; Remarks .......: Proper errorchecking is not on the ToDo list ; Related .......: _BuildScript ; =============================================================================================================================== Func _RunScript($script) Local $path = @TempDir & "\SolveIt.au3", $line, $PID FileWrite($path,$script) $PID = Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & $path & '"',@ScriptDir,@SW_HIDE,0x02) While 1 $line &= StdoutRead($PID) If @error Then ExitLoop Wend FileDelete($path) $line = StringTrimRight($line,1) Return StringSplit($line,",") EndFunc It generates a custom function for the given parameters and then executes that through @AutoItExe as $STDOUT_CHILD. Not sure if people will approve of this method, but I was bored and this was something new for me. Edited June 4, 2010 by Tvern 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