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
:/
@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...