homa
 Guru
 Joined: 05/11/2021 Location: GermanyPosts: 658 |
| Posted: 10:10pm 09 Aug 2026 |
Copy link to clipboard |
 Print this post |
|
Hello,
i had the idea to program Mastermind while on vacation. I started by having the computer generate the code and handle checking my input and the peg output. Then, I thought the computer should also be able to solve the game. I programmed a solution using only BASIC. Solving the first 4/6-move problem took 7–10 minutes. As the number of combinations increased, it took about 30 minutes. Then, I had the idea to offload this part to C, but since I’m not familiar with it, I asked the AI for help.
Attached is the final result, which took two to three days of reading, learning, and experimenting to achieve, along with a small terminal game. That's why I still use numbers instead of colors, even though it's called “Cols” ;-)
The limits with FW 6.03.01 are pegs/cols: rp2040: 5/6 rp2040 FW MIN: 5/7 rp2350 / PicoCalc (with display): 5/8
Have fun! I’d appreciate any feedback on improvements or confirmation that this was solved correctly using the CSUB.
Next step: a nice GUI? Perhaps for the PicoCalc and Game*Mite?
Matthias
======================================= b a s i - c - m i n d ======================================= Cfg: 5 Pegs, 8 Cols ( 32768 Max) RAM: ~ 256 KB (Free: ~ 41 KB) --------------------------------------- 1. Play vs AI (with Hints) 2. AI Solves Your Code 3. Setup (Dynamic RAM Check) 0. Exit --------------------------------------- Select (0-3):
======================================= MODE 2: COMPUTER SOLVER ======================================= Secret code ( 5 digits 1- 8): 23114 # 1: 33776 (0.3ms) -> 1B, 0W Remaining candidates: 3796 # 2: 31111 (4666.1ms) -> 2B, 1W Remaining candidates: 87 # 3: 23211 (7.9ms) -> 3B, 1W Remaining candidates: 6 # 4: 23141 (2.8ms) -> 3B, 2W Remaining candidates: 1 # 5: 23114 (0.2ms) -> 5B, 0W --------------------------------------- AI Solved in 5 moves! Press any key...
' ======================================= ' b a s i - c - m i n d ' ver 1.0 ' Hybrid Mastermind Solver for PicoCalc ' Universal Dynamic Memory Version ' Works on: RP2040, RP2350 & MMBasic ' 2026 by homa with the help of AI ' =======================================
OPTION BASE 0
' --- Default Configuration --- DIM INTEGER mN = 4 ' 4 to 5 Pegs DIM INTEGER mC = 6 ' 6 to 8 Colors DIM INTEGER totalCodes = mC ^ mN
' --- Re-allocation Signals --- DIM INTEGER reallocFlag = 0 DIM INTEGER reqN = 4 DIM INTEGER reqC = 6
' --- Master Variables & CSub --- DIM INTEGER params(6) DIM candIndices(totalCodes - 1) AS INTEGER DIM INTEGER candCount
RANDOMIZE TIMER ResetCandidates
' ======================================= ' MAIN LOOP (Root Level Allocation) ' ======================================= DO ' Safely reallocate memory outside of SUBs IF reallocFlag = 1 THEN ERASE candIndices mN = reqN mC = reqC totalCodes = mC ^ mN DIM candIndices(totalCodes - 1) AS INTEGER reallocFlag = 0 ResetCandidates END IF MainMenu LOOP END
' ======================================= ' MENUS & INITIALIZATION ' ======================================= SUB ClearScreen PRINT CHR$(27) + "[2J" + CHR$(27) + "[H"; ON ERROR SKIP CLS END SUB
SUB MainMenu LOCAL choice AS INTEGER ClearScreen PRINT "=======================================" PRINT " b a s i - c - m i n d " PRINT "=======================================" PRINT "Cfg: "; mN; " Pegs, "; mC; " Cols ("; totalCodes; " Max)" PRINT "RAM: ~"; INT((totalCodes * 8) / 1024); " KB (Free: ~"; INT(MM.INFO(HEAP)/1024); " KB)" PRINT "---------------------------------------" PRINT "1. Play vs AI (with Hints)" PRINT "2. AI Solves Your Code" PRINT "3. Setup (Dynamic RAM Check)" PRINT "0. Exit" PRINT "---------------------------------------" INPUT "Select (0-3): ", choice SELECT CASE choice CASE 1: PlayHumanMode CASE 2: PlayAIMode CASE 3: ChangeConfig CASE 0: END END SELECT END SUB
SUB ChangeConfig LOCAL newN AS INTEGER, newC AS INTEGER LOCAL neededBytes AS INTEGER, totalHeap AS INTEGER PRINT "" PRINT "--- New Configuration ---" INPUT "Pegs (4 to 5) : ", newN INPUT "Colors (6 to 8): ", newC ' Strict Limits Check IF (newN < 4 OR newN > 5) OR (newC < 6 OR newC > 8) THEN PRINT "Error: 4-5 Pegs and 6-8 Colors only!" PRINT "Press any key..." DO WHILE INKEY$ = "": LOOP EXIT SUB END IF neededBytes = (newC ^ newN) * 8 ' Available Heap after erasing old array (minus 10KB safety margin) totalHeap = MM.INFO(HEAP) + (totalCodes * 8) - 10240 PRINT "" PRINT "RAM Check:" PRINT " Need: ~"; INT(neededBytes / 1024); " KB" PRINT " Free: ~"; INT(totalHeap / 1024); " KB" IF neededBytes > totalHeap THEN PRINT "---------------------------------------" PRINT "ERROR: Memory limit exceeded!" PRINT INT(neededBytes / 1024); " KB required, but only" PRINT INT(totalHeap / 1024); " KB safely available." PRINT "Reduce Pegs/Colors or use larger MCU." PRINT "Press any key..." DO WHILE INKEY$ = "": LOOP EXIT SUB END IF ' Signal root loop to reallocate reqN = newN reqC = newC reallocFlag = 1 PRINT "Settings saved! Press any key..." DO WHILE INKEY$ = "": LOOP END SUB
' ======================================= ' MODE 1: HUMAN GUESSES (+ AI HINT) ' ======================================= SUB PlayHumanMode LOCAL secret(mN-1) AS INTEGER, guess(mN-1) AS INTEGER LOCAL c AS INTEGER, pb AS INTEGER, pw AS INTEGER LOCAL attempts AS INTEGER = 0 LOCAL sIdx AS INTEGER, gIdx AS INTEGER LOCAL inStr$ AS STRING, tStart AS FLOAT, tEnd AS FLOAT ResetCandidates FOR c = 0 TO mN - 1 secret(c) = INT(RND * mC) + 1 NEXT c sIdx = ArrayToIndex(secret()) ClearScreen PRINT "=======================================" PRINT " MODE 1: HUMAN VS COMPUTER " PRINT "[H] Hint | [S] Surrender" PRINT "=======================================" DO attempts = attempts + 1 PRINT "Move "; attempts; " (Remaining: "; candCount; ")" DO PRINT "Guess "; mN; " digits (1-"; mC; "): "; INPUT "", inStr$ inStr$ = UCASE$(inStr$) IF inStr$ = "H" THEN PRINT " AI thinking... "; tStart = TIMER IF attempts = 1 THEN gIdx = GetRandomOpening() ELSE gIdx = GetBestGuessCSub() END IF tEnd = TIMER PRINT "Try: "; CodeToString$(gIdx); " ("; STR$((tEnd-tStart),1,1); "ms)" ELSEIF inStr$ = "S" THEN PRINT "Surrender! Secret was: "; CodeToString$(sIdx) PRINT "Press any key..." DO WHILE INKEY$ = "": LOOP EXIT SUB ELSEIF ParseInput(inStr$, guess()) THEN EXIT DO ELSE PRINT "Invalid input!" END IF LOOP gIdx = ArrayToIndex(guess()) GetScoregIdx gIdx, sIdx, pb, pw PRINT "-> Result: "; pb; " Black, "; pw; " White" PRINT "---------------------------------------" IF pb = mN THEN PRINT "SUCCESS! Solved in "; attempts; " moves!" PRINT "Press any key..." DO WHILE INKEY$ = "": LOOP EXIT SUB END IF FilterCSub gIdx, pb, pw LOOP END SUB
' ======================================= ' MODE 2: COMPUTER SOLVER ' ======================================= SUB PlayAIMode LOCAL secStr$ AS STRING, sIdx AS INTEGER, gIdx AS INTEGER LOCAL pb AS INTEGER, pw AS INTEGER, stepCount AS INTEGER = 1 LOCAL tStart AS FLOAT, tEnd AS FLOAT ClearScreen PRINT "=======================================" PRINT " MODE 2: COMPUTER SOLVER " PRINT "=======================================" PRINT "Secret code ("; mN; " digits 1-"; mC; "): "; INPUT "", secStr$ sIdx = CodeTextToIndex(secStr$) IF sIdx = -1 THEN PRINT "Invalid code! Press any key..." DO WHILE INKEY$ = "": LOOP EXIT SUB END IF ResetCandidates DO tStart = TIMER IF stepCount = 1 THEN gIdx = GetRandomOpening() ELSE gIdx = GetBestGuessCSub() END IF tEnd = TIMER GetScoregIdx gIdx, sIdx, pb, pw PRINT "#"; stepCount; ": "; CodeToString$(gIdx); " ("; STR$((tEnd - tStart), 1, 1); "ms) -> "; pb; "B, "; pw; "W" IF pb = mN THEN PRINT "---------------------------------------" PRINT "AI Solved in "; stepCount; " moves!" PRINT "Press any key..." DO WHILE INKEY$ = "": LOOP EXIT SUB END IF FilterCSub gIdx, pb, pw PRINT " Remaining candidates: "; candCount stepCount = stepCount + 1 LOOP END SUB
' ======================================= ' CSUB & LOGIC HELPERS ' ======================================= SUB FilterCSub(gIdx AS INTEGER, b AS INTEGER, w AS INTEGER) params(0) = 1 params(1) = gIdx params(2) = candCount params(3) = b params(4) = w params(5) = mN params(6) = mC
MasterMindCSub params(0), candIndices(0) candCount = params(2) END SUB
FUNCTION GetBestGuessCSub() AS INTEGER params(0) = 2 params(1) = mN params(2) = totalCodes params(3) = candCount params(4) = 0 params(5) = mC
MasterMindCSub params(0), candIndices(0) GetBestGuessCSub = params(4) END FUNCTION
FUNCTION GetRandomOpening() AS INTEGER LOCAL c1 AS INTEGER, c2 AS INTEGER, c3 AS INTEGER c1 = INT(RND * mC) DO: c2 = INT(RND * mC): LOOP WHILE c2 = c1 IF mN = 4 THEN GetRandomOpening = c1 + c1 * mC + c2 * (mC^2) + c2 * (mC^3) ELSEIF mN = 5 THEN DO: c3 = INT(RND * mC): LOOP WHILE c3 = c1 OR c3 = c2 GetRandomOpening = c1 + c1 * mC + c2 * (mC^2) + c2 * (mC^3) + c3 * (mC^4) ELSE GetRandomOpening = candIndices(INT(RND * candCount)) END IF END FUNCTION
SUB ResetCandidates LOCAL i AS INTEGER candCount = totalCodes FOR i = 0 TO totalCodes - 1 candIndices(i) = i NEXT i END SUB
FUNCTION ParseInput(in$ AS STRING, arr() AS INTEGER) AS INTEGER LOCAL i AS INTEGER, valDigit AS INTEGER IF LEN(in$) <> mN THEN ParseInput = 0: EXIT FUNCTION FOR i = 1 TO mN valDigit = VAL(MID$(in$, i, 1)) IF valDigit < 1 OR valDigit > mC THEN ParseInput = 0: EXIT FUNCTION arr(i - 1) = valDigit NEXT i ParseInput = 1 END FUNCTION
FUNCTION ArrayToIndex(arr() AS INTEGER) AS INTEGER LOCAL i AS INTEGER, idx AS INTEGER = 0, mult AS INTEGER = 1 FOR i = 0 TO mN - 1 idx = idx + (arr(i) - 1) * mult mult = mult * mC NEXT i ArrayToIndex = idx END FUNCTION
SUB GetScoregIdx(gIdx AS INTEGER, sIdx AS INTEGER, b AS INTEGER, w AS INTEGER) LOCAL i AS INTEGER, c AS INTEGER, dg AS INTEGER, ds AS INTEGER LOCAL gCnt(8) AS INTEGER, sCnt(8) AS INTEGER LOCAL tempG AS INTEGER = gIdx, tempS AS INTEGER = sIdx b = 0: w = 0 FOR i = 0 TO 8: gCnt(i) = 0: sCnt(i) = 0: NEXT i FOR i = 0 TO mN - 1 dg = tempG MOD mC: ds = tempS MOD mC IF dg = ds THEN b = b + 1 ELSE gCnt(dg) = gCnt(dg) + 1: sCnt(ds) = sCnt(ds) + 1 END IF tempG = tempG \ mC: tempS = tempS \ mC NEXT i FOR c = 0 TO mC - 1 IF gCnt(c) > 0 AND sCnt(c) > 0 THEN IF gCnt(c) < sCnt(c) THEN w = w + gCnt(c) ELSE w = w + sCnt(c) END IF NEXT c END SUB
FUNCTION CodeToString$(idx AS INTEGER) AS STRING LOCAL s$ AS STRING = "", peg AS INTEGER, temp AS INTEGER = idx FOR peg = 0 TO mN - 1 s$ = s$ + STR$((temp MOD mC) + 1) temp = temp \ mC NEXT peg CodeToString$ = s$ END FUNCTION
FUNCTION CodeTextToIndex(code$ AS STRING) AS INTEGER LOCAL i AS INTEGER, digit AS INTEGER, idx AS INTEGER = 0, mult AS INTEGER = 1 IF LEN(code$) <> mN THEN CodeTextToIndex = -1: EXIT FUNCTION FOR i = 1 TO mN digit = VAL(MID$(code$, i, 1)) - 1 IF digit < 0 OR digit >= mC THEN CodeTextToIndex = -1: EXIT FUNCTION idx = idx + digit * mult mult = mult * mC NEXT i CodeTextToIndex = idx END FUNCTION
' CSub Embed Block CSub MasterMindCSub INTEGER, INTEGER 00000000 46DEB5F0 46464657 6803B5C0 9046B0EE 2B019142 E2ADD100 D0072B02 21002000 BCE0B06E 46B246BB BDF046A8 69999B46 2900913F F000DC01 9A42FF1C 92406898 6A9F2200 9343008B 92410083 3201903E 9B409301 681B993E DC012900 FF45F000 468B2100 910E910F 2182E1C2 468A0209 02092186 21844688 468C0209 0209218A 218E9102 91030209 0209218C 21889104 91050209 02092192 21969106 91070209 02092194 219A9108 91090209 0209219E 219C910A 910B0209 02092198 2190910C 910D0209 020921A2 21A69110 91110209 020921A4 21AA9112 91130209 020921AE 21AC9114 91150209 020921A8 21B29116 91170209 020921B6 21B49118 91190209 020921BA 21BE911A 911B0209 020921BC 21B8911C 911D0209 020921B0 21A0911E 911F0209 020921C2 21C69120 91210209 020921C4 21CA9122 91230209 020921CE 21CC9124 91250209 020921C8 21D29126 91270209 020921D6 21D49128 91290209 020921DA 21DE912A 912B0209 020921DC 21D8912C 912D0209 020921D0 21E2912E 912F0209 020921E6 21E49130 91310209 020921EA 21EE9132 91330209 020921EC 21E89134 91350209 020921F2 21F69136 91370209 020921F4 21FA9138 91390209 020921FE 21FC913A 913B0209 24C021F8 913C0209 26F00221 913D25E0 1BC02180 022D0236 00440209 40100B98 42874320 9920D83D 468A1BC0 46889921 468C9922 91029923 91039924 91049925 91059926 91069927 91079928 91089929 9109992A 910A992B 910B992C 910C992D 910D992E 9110992F 91119930 91129931 961E9932 99339113 9114951F 91159934 91169935 91179936 91189937 91199938 911A9939 911B993A 911C993B 911D993C 0B5C993D 40140040 42B84320 9910D31F 468A1BC0 46889911 468C9912 91029913 91039914 91049915 91059916 91069917 91079918 91089919 9109991A 910A991B 910B991C 910C991D 910D991E 0B1C991F 40140040 42BC4304 9906D30F 468A1BE4 46889907 468C9908 91029909 9103990A 9104990B 9105990C 0AD8990D 40100064 42B84320 9902D307 468A1BC0 46889903 468C9904 0A9C9905 40140040 42BC4304 46C2D302 1BE44661 00640A58 43204010 D30142B8 1BC04651 00400A1C 43044014 D30342BC 00402080 43011BE4 006409D8 43204010 D30242B8 1BC02480 099C4321 40140040 42BC4304 2040D302 43011BE4 00640958 43204010 D30242B8 1BC02420 091C4321 40140040 42BC4304 2010D302 43011BE4 006408D8 43204010 D30242B8 1BC02408 089C4321 40140040 42BC4304 2004D302 43011BE4 00640858 43204010 D30242B8 1BC02402 00404321 43034013 D30142BB 43111BDB 0098465C 9C0E40A3 0013431C 980F4083 4684940E 4663449C 2304930F 9B01469C 459B44E3 F000D101 000BFD81 40100BD8 D8004287 2180E637 468A0089 00C921C0 21804688 468C00C9 010921A0 21E09102 91030109 010921C0 21809104 91050109 01492190 21B09106 91070149 014921A0 21D09108 91090149 014921F0 21E0910A 910B0149 014921C0 2180910C 910D0149 01892188 21989110 91110189 01892190 21A89112 91130189 018921B8 21B09114 91150189 018921A0 21C89116 91170189 018921D8 21D09118 91190189 018921E8 21F8911A 911B0189 018921F0 21E0911C 911D0189 018921C0 2180911E 911F0189 01C92184 218C9120 912101C9 01C92188 21949122 912301C9 01C9219C 21989124 912501C9 01C92190 21A49126 912701C9 01C921AC 21A89128 912901C9 01C921B4 21BC912A 912B01C9 01C921B8 21B0912C 912D01C9 01C921A0 21C4912E 912F01C9 01C921CC 21C89130 913101C9 01C921D4 21DC9132 913301C9 01C921D8 21D09134 913501C9 01C921E4 21EC9136 913701C9 01C921E8 21F49138 913901C9 01C921FC 21F8913A 913B01C9 248021F0 25C026E0 913C01C9 913D01E1 210001F6 E63801ED 69020003 6982923C 92436A80 90446A1A 001A9249 68916B1B 28002200 F000DC01 0080FE64 923E4694 903B923F 0BCD3201 42AB4015 F000D901 2084FD80 46800200 0200208A 208E4682 46830200 0200208C 20889001 90020200 02002092 20969003 90040200 02002094 209A9005 90060200 0200209E 209C9007 90080200 02002098 20909009 900A0200 020020A2 20A6900B 900C0200 020020A4 20AA900D 900E0200 020020AE 20AC900F 90100200 020020A8 20B29011 90120200 020020B6 20B49013 90140200 020020BA 20BE9015 90160200 020020BC 20B89017 90180200 020020B0 20A09019 901A0200 020020C2 20C6901B 901C0200 020020C4 20CA901D 901E0200 020020CE 20CC901F 90200200 020020C8 20D29021 90220200 020020D6 20D49023 90240200 020020DA 20DE9025 90260200 020020DC 20D89027 90280200 020020D0 20E29029 902A0200 020020E6 20E4902B 902C0200 020020EA 20EE902D 902E0200 020020EC 20E8902F 90300200 020020F2 20F69031 90320200 020020F4 20FA9033 90340200 020020FE 20FC9035 90360200 020020F8 20F09037 90380200 020020E0 20C09039 26820200 903A2786 1AED2080 023F0236 0B8C0200 4014006D 42A3432C 981DD83D 46809E1B 9F1C981E 981F4682 46831AE4 90019820 90029821 90039822 90049823 90059824 90069825 90079826 90089827 90099828 900A9829 900B982A 900C982B 900D982C 900E982D 900F982E 9010982F 90119830 90129831 90139832 90149833 90159834 90169835 90179836 90189837 90199838 901A9839 0B4D983A 40150064 42AB4325 980DD81D 46809E0B 9F0C980E 980F4682 46831AED 90019810 90029811 90039812 90049813 90059814 90069815 90079816 90089817 90099818 900A9819 0B0C981A 4014006D 42A3432C 9805D80D 46809E03 9F049806 98074682 46831AE4 90019808 90029809 0ACD980A 40150064 42AB4325 4656D805 9801465F 46801AED 0A8C9802 4014006D 42A3432C 003ED802 1AE44640 00640A4D 432C4015 D80142A3 1AE40030 00640A0D 43254015 D80342AB 00642480 43201AED 006D09CC 432C4014 D80242A3 1AE42580 098D4328 40150064 42AB4325 2440D802 43201AED 006D094C 432C4014 D80242A3 1AE42520 090D4328 40150064 42AB4325 2410D802 43201AED 006D08CC 432C4014 D80242A3 1AE42508 088D4328 40150064 42AB4325 2404D802 43201AED 006D084C 432C4014 D80242A3 1AE42502 00644328 43214011 D900428B 4665E3BE 00011ACC 40AC00A0 43119D3F 00144325 00204084 953F9C3E 448046A0 903E4640 46802004 44C4983B D0004560 9A3CE63B DC012A00 FC99F000 00D29942 4462468C 22009245 21019141 9A449248 920F0092 9240009A 98449A41 92476812 DC012800 FC78F000 46832000 90029001 2082E1C1 46840200 02002086 20844680 46820200 0200208A 208E9003 90040200 0200208C 20889005 90060200 02002092 20969007 90080200 02002094 209A9009 900A0200 0200209E 209C900B 900C0200 02002098 2090900D 900E0200 020020A2 20A69010 90110200 020020A4 20AA9012 90130200 020020AE 20AC9014 90150200 020020A8 20B29016 90170200 020020B6 20B49018 90190200 020020BA 20BE901A 901B0200 020020BC 20B8901C 901D0200 020020B0 20A0901E 901F0200 020020C2 20C69020 90210200 020020C4 20CA9022 90230200 020020CE 20CC9024 90250200 020020C8 20D29026 90270200 020020D6 20D49028 90290200 020020DA 20DE902A 902B0200 020020DC 20D8902C 902D0200 020020D0 20E2902E 902F0200 020020E6 20E49030 90310200 020020EA 20EE9032 90330200 020020EC 20E89034 90350200 020020F2 20F69036 90370200 020020F4 20FA9038 90390200 020020FE 20FC903A 903B0200 25C020F8 903C0200 27F00228 903D26E0 1AE42080 0236023F 00650200 400C0B94 42A3432C 9820D83D 46841AE4 46809821 46829822 90039823 90049824 90059825 90069826 90079827 90089828 90099829 900A982A 900B982B 900C982C 900D982D 900E982E 9010982F 90119830 90129831 971E9832 98339013 9014961F 90159834 90169835 90179836 90189837 90199838 901A9839 901B983A 901C983B 901D983C 0B55983D 400D0064 42AB4325 9810D81F 46841AED 46809811 46829812 90039813 90049814 90059815 90069816 90079817 90089818 90099819 900A981A 900B981B 900C981C 900D981D 900E981E 006C981F 400D0B15 42AB4325 9807D80F 46841AED 46809808 46829809 9003980A 9004980B 9005980C 9006980D 0AD4980E 400C006D 42A3432C 9803D807 46841AE4 46809804 46829805 0A959806 400D0064 42AB4325 46C4D802 1AED4650 006D0A54 432C400C D80142A3 1AE44660 00640A15 4325400D D80342AB 00642480 43201AED 006D09D4 432C400C D80242A3 1AE42580 09954328 400D0064 42AB4325 2440D802 43201AED 006D0954 432C400C D80242A3 1AE42520 09154328 400D0064 42AB4325 2410D802 43201AED 006D08D4 432C400C D80242A3 1AE42508 08954328 400D0064 42AB4325 2404D802 43201AED 006D0854 432C400C D80242A3 1AE42502 00644328 4322400A D8014293 43081AD2 0094465D 9D0240AA 000A4315 9C0140A2 46A49502 46624494 22049201 9A0F4694 455A44E3 E0C9D100 0BD40002 42A3400C E638D800 00802080 20C04684 468000C0 00C02080 20A04682 90030100 010020E0 20C09004 90050100 01002080 20909006 90070140 014020B0 20A09008 90090140 014020D0 20F0900A 900B0140 014020E0 20C0900C 900D0140 01402080 2088900E 90100180 01802098 20909011 90120180 018020A8 20B89013 90140180 018020B0 20A09015 90160180 018020C8 20D89017 90180180 018020D0 20E89019 901A0180 018020F8 20F0901B 901C0180 018020E0 20C0901D 901E0180 01802080 2084901F 902001C0 01C0208C 20889021 902201C0 01C02094 209C9023 902401C0 01C02098 20909025 902601C0 01C020A4 20AC9027 902801C0 01C020A8 20B49029 902A01C0 01C020BC 20B8902B 902C01C0 01C020B0 20A0902D 902E01C0 01C020C4 20CC902F 903001C0 01C020C8 20D49031 903201C0 01C020DC 20D89033 903401C0 01C020D0 20E49035 903601C0 01C020EC 20E89037 903801C0 01C020F4 20FC9039 903A01C0 01C020F8 20F0903B 27E02580 01C026C0 01E8903C 01FF903D 01F62000 2300E639 99462200 624A620B F8CEF7FF 25002000 9E02240F 40729A3F 402240C2 41724256 9A0F18AD 42823004 2B00D1F3 E1D3DC00 26002000 9C01270F 40C49A3E 403C40C2 3004403A D90042A2 19960022 42909A40 9A43D1F1 D10042AA 9A41E1AD 32089845 42829241 E539D000 17DA9B48 610B9946 F7FF614A 2300F899 930E930F 99419B40 93403308 980E4BDC 5058447B 980F4BDB 5058447B 99431D0B 428B9341 F7FFD001 2301F89E 930B24C8 00A49B42 930F681B 42A39B3F 2500DD16 2300221F 993F2001 40D1005B 430B4001 D30542A3 468C49CC 40910001 430D4463 D2F03A01 2D00950B E17FDC00 425B2301 2300930A AB6E9309 4BC49303 447B200F 930D469C 9A434BC2 930E447B 44629B3E 93083301 469A00BB 9207AB4A 9B069306 001D9A09 00D29942 920C588A C3042200 42939A03 9B09D1FA 990D9A0E 9104009B 58D358C9 4698468C 9B049205 9302681B 681E9B05 2B009B3E 2200DD54 46632400 404B9902 400340D3 424B0019 18E4414B 32049B01 D1F24293 43639B08 2F009302 2300DD3D 469B2200 46430031 40D340D1 40034001 428B3204 000BD900 4552449B 9A02D1F2 4693465B 9A051B1B 445B9C06 3204009B 58E29205 32019904 9B0750E2 91043104 D1C0428B 682B2200 2B003504 435BDD01 9B0318D2 D1F6429D 42939B0A 9B0CD902 930F920A 9B099A0B 9A3F4694 93094463 DC92429A 17DA9B0F 2300E705 E7CE469B 24002300 E7B89302 008C4665 9D3F40A9 0011430D 9C3E40A1 46A0953F 46414488 2104913E 993B4688 456144C4 E444D100 0BCD0001 42AB4015 F7FFD801 2080FA80 468000C0 010020A0 20E04682 46830100 010020C0 20809001 90020100 01402090 20B09003 90040140 014020A0 20D09005 90060140 014020F0 20E09007 90080140 014020C0 20809009 900A0140 01802088 2098900B 900C0180 01802090 20A8900D 900E0180 018020B8 20B0900F 90100180 018020A0 20C89011 90120180 018020D8 20D09013 90140180 018020E8 20F89015 90160180 018020F0 20E09017 90180180 018020C0 20809019 901A0180 01C02084 208C901B 901C01C0 01C02088 2094901D 901E01C0 01C0209C 2098901F 902001C0 01C02090 20A49021 902201C0 01C020AC 20A89023 902401C0 01C020B4 20BC9025 902601C0 01C020B8 20B09027 902801C0 01C020A0 20C49029 902A01C0 01C020CC 20C8902B 902C01C0 01C020D4 20DC902D 902E01C0 01C020D8 20D0902F 903001C0 01C020E4 20EC9031 903201C0 01C020E8 20F49033 903401C0 01C020FC 20F89035 903601C0 01C020F0 20E09037 903801C0 01C020C0 20809039 27C02680 903A01C0 200000B6 F7FF00FF 1AB6FA80 42B29A49 E64CD000 9C489842 00E24684 44629847 17C06010 1C626050 E6409248 E63A2600 25002200 E6229201 930B2301 923EE67C F7FF923F 2300FB62 E6392200 000003C0 000203B8 FFFFFCE0 00000352 00020348 End CSub
#pragma GCC optimize ("O3") #pragma GCC optimize ("no-tree-loop-distribute-patterns")
#include "PicoCFunctions.h"
// Software-32-Bit-Division (verhindert __aeabi_idiv Aufruf durch den Compiler!) static inline __attribute__((always_inline)) unsigned int fast_div32( unsigned int dividend, unsigned int divisor) { if (divisor == 0) return 0; unsigned int q = 0, r = 0; for (int i = 31; i >= 0; i--) { r = (r << 1) | ((dividend >> i) & 1); if (r >= divisor) { r -= divisor; q |= (1U << i); } } return q; }
// 16-Bit Division/Modulo für Index-Umrechnung static inline __attribute__((always_inline)) void fast_divmod16( unsigned int dividend, unsigned int divisor, unsigned int *quotient, unsigned int *remainder) { unsigned int q = 0, r = 0; for (int i = 15; i >= 0; i--) { r = (r << 1) | ((dividend >> i) & 1); if (r >= divisor) { r -= divisor; q |= (1U << i); } } *quotient = q; *remainder = r; }
// Erstellt gepackten Code + Farbanzahlen in einem Rutsch static inline __attribute__((always_inline)) void index_to_packed_and_counts( int idx, int num_pegs, int num_colors, unsigned int *out_code, unsigned int *out_counts) { unsigned int packed = 0; unsigned int counts = 0; unsigned int temp = (unsigned int)idx; unsigned int u_colors = (unsigned int)num_colors;
for (int peg = 0; peg < num_pegs; peg++) { unsigned int q, r; fast_divmod16(temp, u_colors, &q, &r); packed |= (r << (peg * 4)); counts += (1U << (r * 4)); temp = q; } *out_code = packed; *out_counts = counts; }
// Ultra-schnelle Auswertung (Schwarz & Weiß) static inline __attribute__((always_inline)) void get_score_fast( unsigned int g_code, unsigned int g_counts, unsigned int s_code, unsigned int s_counts, int num_pegs, int num_colors, int *out_b, int *out_w) { int black = 0; for (int p = 0; p < num_pegs; p++) { if (((g_code >> (p * 4)) & 0xF) == ((s_code >> (p * 4)) & 0xF)) { black++; } }
int total_matches = 0; for (int c = 0; c < num_colors; c++) { unsigned int gc = (g_counts >> (c * 4)) & 0xF; unsigned int sc = (s_counts >> (c * 4)) & 0xF; total_matches += (gc < sc) ? gc : sc; }
*out_b = black; *out_w = total_matches - black; }
// C-RAM Puffer (128 KB) static unsigned int cand_codes_cache[32768]; static unsigned int cand_counts_cache[32768];
// DIE EINZIGE CSUB-FUNKTION long long MasterMindCSub(long long *params, long long *cand_indices) { int cmd = (int)params[0];
// ========================================================================= // BEFEHL 1: Schnelles Filtern der Kandidaten in C (Blitzschnell!) // ========================================================================= if (cmd == 1) { int gIdx = (int)params[1]; int cand_count = (int)params[2]; int targetB = (int)params[3]; int targetW = (int)params[4]; int num_pegs = (int)params[5]; int num_colors = (int)params[6];
unsigned int g_code, g_counts; index_to_packed_and_counts(gIdx, num_pegs, num_colors, &g_code, &g_counts);
int new_count = 0; for (int i = 0; i < cand_count; i++) { int sIdx = (int)cand_indices[i]; unsigned int s_code, s_counts; index_to_packed_and_counts(sIdx, num_pegs, num_colors, &s_code, &s_counts);
int b, w; get_score_fast(g_code, g_counts, s_code, s_counts, num_pegs, num_colors, &b, &w);
if (b == targetB && w == targetW) { cand_indices[new_count] = sIdx; new_count++; } } params[2] = (long long)new_count; return 0; }
// ========================================================================= // BEFEHL 2: Besten Zug berechnen (GetBestGuess) // ========================================================================= if (cmd == 2) { int num_pegs = (int)params[1]; int total_codes = (int)params[2]; int cand_count = (int)params[3]; int num_colors = (int)params[5];
if (cand_count <= 0) { params[4] = 0; return 0; }
for (int j = 0; j < cand_count; j++) { int sIdx = (int)cand_indices[j]; index_to_packed_and_counts(sIdx, num_pegs, num_colors, &cand_codes_cache[j], &cand_counts_cache[j]); }
int best_idx = (int)cand_indices[0]; unsigned int min_score = 0xFFFFFFFFU; // Eigenes fast_div32 verhindert den Aufruf von __aeabi_idiv! int step = 1; if (cand_count > 800) { step = (int)fast_div32((unsigned int)cand_count, 800); if (step < 1) step = 1; }
int counts[36];
for (int i = 0; i < cand_count; i += step) { int gIdx = (int)cand_indices[i]; volatile int *vc = counts; for (int k = 0; k < 36; k++) vc[k] = 0;
unsigned int g_code = cand_codes_cache[i]; unsigned int g_counts = cand_counts_cache[i];
for (int j = 0; j < cand_count; j++) { int b, w; get_score_fast(g_code, g_counts, cand_codes_cache[j], cand_counts_cache[j], num_pegs, num_colors, &b, &w); int score_idx = b * (num_pegs + 1) + w; counts[score_idx]++; }
unsigned int sum_sq = 0; for (int k = 0; k < 36; k++) { int cnt = counts[k]; if (cnt > 0) { sum_sq += (unsigned int)cnt * (unsigned int)cnt; } }
if (sum_sq < min_score) { min_score = sum_sq; best_idx = gIdx; } }
params[4] = (long long)best_idx; return 0; }
return 0; }
|