Gracias por sus respuestas, pero creo que no me exprese bien, tratare de explicarme un poco mejor.
El usuario da de alta cada tanto nuevos clientes, en el momento del alta, el sistema le asigna a ese cliente un cartón generado aleatoriamente que no debe estar asignado a ningún otro cliente previo.
En la base de datos, se guardan los clientes y los cartones que tiene asociado cada uno.
El problema es como generar un cartón QUE NO ESTE ASIGNADO A NINGÚN OTRO CLIENTE de los que ya están registrados.
Levantar a memoria todos los cartones registrados para luego armar uno nuevo, puede voltearme el server ya que van a ser muchísimos.
Se me ocurrió otra posibilidad que es muy viable y genérica, pero que no logro hacerla funcionar, la idea es esta:
Dado un conjunto de elementos cualquiera, se pueden obtener una lista de todas sus combinaciones de elementos de forma ordenada sin problemas, ahora, si pudiera obtener directamente una combinación de esa lista, sin calcular las demás, podría guardar el numero de carton del cliente como un entero comun, y luego al vuelo obtener la combinacion de numeros correspondiente.
El problema que tengo es que no logro que la funcion ande, ¿Me podrían dar una mano?
Código PHP:
Ver original<?php
function factorial($numero)
{
$fact = 1;
while($numero >= 1 && ($fact *= $numero--));
return $fact;
}
function combinatoria($m, $n)
{
return (factorial($m) / (factorial($n) * factorial($m - $n)));
}
// Esta funcion obtiene la combinacion de una posicion.
// Items es un array con los elementos
// $n el numero de elementos por carton
// $pos es la posicion que me interesa
function cartones($items, $n, $pos)
{
// Aca se guardan los items del carton
$combinacion = [];
// Cuantos items hay
// Auxiliares
$base = 0;
$idx = -1;
// Mientras me falte algun elemento en la combinacion
while($n)
{
//echo "<hr>";
// Numero de combinaciones posibles
$posibles = combinatoria($m, $n);
// Para cada variacion de 1 elemento posible
for($nro=0; $nro<$m-$n+1; $nro++)
{
// Desde donde arranca ese elemento
$desde = $base + $posibles - combinatoria($m - $nro, $n);
// Hasta donde termina ese elemento
$hasta = $base + $posibles - combinatoria($m - $nro - 1, $n) - 1;
$idx++;
//echo "Rango: $desde - $hasta | $pos<br>";
// Si la posicion que busco esta dentro de ese rango
// NOTA: La segunda parte, luego del or, esta puesta como parche, pero no le encuentro logica
if(($pos >= $desde && $pos <= $hasta) || ($hasta < $desde && $pos == $desde))
{
// Guardar el origen del grupo como punto de partida
$base = $desde;
//echo "Ok!<br>";
// Agregar al carton el item correspondiente.
$combinacion[] = $items[$idx];
break;
}
}
$m--;
$n--;
}
return $combinacion;
}
//var_dump(cartones(range(0, 9), 4, 34));
// Tests
// Genero todas las combinaciones posibles de 9 elementos tomados de a 4 y los comparo con los de la funcion para ver cuales fallan
echo "<hr>";
$id = 0;
$fails = 0;
for($a=0; $a<=6; $a++)
{
for($e=$a+1; $e<=9; $e++)
{
for($i=$e+1; $i<=9; $i++)
{
for($o=$i+1; $o<=9; $o++)
{
$carton = cartones
(range(0, 9), 4, $id); if($carton[0] != $a || $carton[1] != $e || $carton[2] != $i || $carton[3] != $o)
{
echo "$id -> [$a, $e, $i, $o] -> [$carton[0], $carton[1], $carton[2], $carton[3]]<br>";
$fails++;
}
else
{
//echo "$id -> Ok!<br>";
}
$id++;
}
}
}
}
echo "Terminado! $fails Fallas";
Para que todo ande los test no deberia fallar ninguno, pero actualmente fallan 140 de 210.
No encuentro como hacerlo andar