Search code examples
sortingbatch-fileduplicatesbatch-processing

Batch Script, need help generating lines of six different numbers (between 1 and 39) that have no more than 2 numbers in common with any previous line


Batch Script, need help generating lines of six different numbers that have no more than 2 numbers in common with any previous line

The goal is to generate a csv file of 300 sets of 6 random numbers between 1 and 39, each set of 6 on a separate line, and each line with a maximum of two numbers in common with any previous line (two numbers with any one line of all previous lines).  That's the goal.  I've hit a snag.  I'm hoping someone might see an easier way.

The script I've made (pieced together) generates a list file without repetition in the row, but the row itself gets longer and longer instead of cutting off at 6.  I also still need the part that checks all previous rows to ensure a max of two duplicates.  If someone has a workaround (a sincere one), I greatly appreciate any to help reach the goal sooner.

Here's the script so far:


@echo off
setlocal enabledelayedexpansion 

for /L %%j in (1 1 10) do (
    call:get_rand
    echo %%j  ;!NUM[1]!;!NUM[2]!;!NUM[3]!;!NUM[4]!;!NUM[5]!;!NUM[6]! >> test.txt

    sort "get_six.txt" >> "get_sort.txt"
    for /f %%b in (get_sort.txt) do findstr "%%~b" "get_tmp.txt" >nul 2>&1 || echo %%b>>"get_tmp.txt"
    call:get_horiz
rem call:del_get_files
)
goto:EOF


rem delete extra files:
rem :del_get_files
rem for %%z in (get_six.txt,get_sort.txt,get_tmp.txt) do (
rem     if exist "%%z" del /q /f "%%z"
rem )
rem goto:EOF


rem get_tmp.txt vertical list to csv horizontal list.txt
:get_horiz
set var=
for /f "tokens=*" %%c in (get_tmp.txt) do (
    call set var=%%var%%,%%c
)
SET var=%var:~1%
echo !var! >> list.txt
goto:EOF


rem get first set of six random numbers
:get_rand
for /L %%i in (1 1 6) do (
    call:get_n %%i
    rem get random number, 1 is the min, 39 is the max
    echo !num[%%i]! >> get_six.txt
)
goto:EOF


rem get random num[%%i] between 1 and 39
:get_n
set /a num[%1] = %RANDOM% * 39 / 32768 + 1
goto:EOF

==========

list.txt (expected):

03,11,17,24,28,37
11,13,25,26,36,39
02,09,15,23,28,37
03,13,14,26,28,32
08,11,21,22,34,36
02,13,16,26,27,31
01,06,14,20,27,31
07,09,20,23,33,34
...

Condition 1: no duplicate numbers per line

Condition 2: not matching more than two numbers with any other line

(I've only checked these visually, I might have missed some, but, for example, the fourth line "03,13,14,26,28,32" has 03 and 28 in common with the first line, "03,11,17,24,28,37", and 13 and 26 with the second, "11,13,25,26,36,39"--that's ok, it's within the permitted maximum)

list.txt (current):

10,28,39 
10,28,39,14,20,22,36 
10,28,39,14,20,22,36,25,34,35 
10,28,39,14,20,22,36,25,34,35,18,31,32 
10,28,39,14,20,22,36,25,34,35,18,31,32,19,29,7 
10,28,39,14,20,22,36,25,34,35,18,31,32,19,29,7,11,17,21,23,33 
10,28,39,14,20,22,36,25,34,35,18,31,32,19,29,7,11,17,21,23,33,12,37 
10,28,39,14,20,22,36,25,34,35,18,31,32,19,29,7,11,17,21,23,33,12,37,24 
10,28,39,14,20,22,36,25,34,35,18,31,32,19,29,7,11,17,21,23,33,12,37,24,15 
10,28,39,14,20,22,36,25,34,35,18,31,32,19,29,7,11,17,21,23,33,12,37,24,15,27

:/


Solution

  • @ECHO OFF
    SETLOCAL ENABLEDELAYEDEXPANSION
    
    :: remove variables starting #
    FOR  /F "delims==" %%e In ('set # 2^>Nul') DO SET "%%e="
    
    SET #combos=0
    
    :newcombo
    SET /a #nums=0
    :: remove variables starting $
    FOR  /F "delims==" %%e In ('set $ 2^>Nul') DO SET "%%e="
    :newrnd
    SET /a nextrand=%RANDOM%
    IF %nextrand% gtr 32759 GOTO newrnd
    SET /a nextrand=101+(nextrand%%39)
    IF DEFINED $%nextrand% GOTO newrnd
    SET "$%nextrand%=%nextrand:~-2%"
    SET /a #nums+=1
    IF %#nums% lss 6 GOTO newrnd
    SET "#c="
    FOR  /F "tokens=2delims==" %%e In ('set $ 2^>Nul') DO SET "#c=!#c!,%%e"
    FOR /L %%y IN (1,1,%#combos%) DO (
     SET /a matchcount=0
     FOR %%o IN (!#c%%y!) DO IF DEFINED $1%%o set/a matchcount+=1
     IF !matchcount! gtr 2 GOTO newcombo
    )
    SET /a #combos+=1
    
    ECHO %#combos% generated
    
    SET "#c%#combos%=%#c:~1%"
    IF %#combos% lss 300 GOTO newcombo
    (
     FOR /L %%y IN (1,1,%#combos%) DO ECHO !#c%%y!
    )>u:\combos.txt
    
    TYPE u:\combos.txt
    
    GOTO :EOF
    

    Well - it'll not break any speed records. Overnight run - at least.

    Set a new random into nextrand. Check that it is not >32759 as values over this would bias the processed random number (which isn't linear in any case)

    Calculate 101+(random mod 39) -> 101..139

    if $selection is set, then that number has already been chosen, so choose again. Otherwise, set $selection to 01..39.

    repeat until we have chosen 6 numbers

    Build #c from $valuesselected values, which will be in sorted order (characteristic of set) and insert commas before each, so #c might become ,05,07,12,17,22,31 for instance

    for each combination already recorded, count the number of matches against the current set of 6 $1xx values chosen. If more than 2 are found, find another combo. Otherwise, record the new combination and count until the limit is reached.

    But - it really is slow...