Página 1 de 1

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 11 Dez 2019 22:57
por Ladinilson Sousa
Boa noite caros,

Possuo um software de sorteio de bingos e para quantidades de cartelas baixo até 30.000 esta tudo muito bom. Mas agora me vejo diante de um desafio muito maior e 500.000 cartelas de teste se tornou lento para trabalhar com DBFCDX diretamente e já testados vários tipo de soluções como:

ORDWILDSEEK()
SET FILTER MEMORY ADDITIVE
SEEK
SET RELATION
ORDSCOPE()

Então tive a última cartada para array na esperança de ser mais rápida e me deparei com algumas dificuldades neste setor que pouco uso.
A ideia é pegar informações do banco de dado original e somente retornar ao mesmo quando alguma cartela já sorteada acontecer.

Comecei com...

PRIVATE aCartelas := {" "," "," "}
SELECT Cartelas
Cartelas->(DBGOTOP())
DbEVal({||AADD(aCartelas,{ALLTRIM(STR(Cartelas->numero)),Cartelas->seqcar,STR(Cartelas->falta)})})

com informações por exemplo...

NUMERO______SEQUENCIA__________________________________________________FALTA
33349________04 07 08 09 11 12 20 22 24 25 33 34 35 40 46 50 51 52 56 59_________20

onde:

NUMERO = Numero da cartela
SEQUENCIA = Sequencia de 20 de numeros da cartela
FALTA = Número de que iá indicar se estará armada ou sorteada (diminuir a cada número encontrado em SEQUENCIA)

A rotina é a cada bola sorteada ele procura se esta contido em SEQUENCIA, caso sim, ele diminui um valor em FALTA (ou seja o valor é substituido no array) isso em cada um elemento de aCartelas

Caso um FALTA esteja com valor 1, ele soma 1 a uma variavel ARMADAS
Caso FALTA fique 0 (zero) atribui-se .T. (verdadeiro) a uma variável GANHOU e atribui-se a uma variável GNUMERO do NUMERO e neste momento darei um SEEK gnumero no campo número do DBFCDX e marcarei o registro (cartela) como sorteada.

Rotina essa dentro de um...
FOR a := 1 TO LEN(aCartelas)
....
NEXT

Parece ser simples mas as sintaxes me fogem a lógica no momento e acredito para experts em arrays isso já deve ser bem simples.

Obrigado pela atenção

Ladinilson Sousa

FWH 13.12/xHarbour/Pelles C/DBFCDX/MySQL

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 12 Dez 2019 20:12
por JoséQuintas
me veio na cabeça:

UPDATE CARTELAS SET FALTA=FALTA-1 WHERE NUMEROS LIKE '%01%'
SELECT * FROM CARTELAS WHERE FALTA = 0

problemão, em SQL com solução simples... rs

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 12 Dez 2019 23:00
por Ladinilson Sousa
José Quintas verdade!

Mas lembrando que os mesmos comandos "varrem" o banco de dados e em se tratando de grandes volumes, a perda de performance pode ser bem significativa pois ha a atualização (COMMIT) ainda.

Em DBFCDX um "$" (está contido) e bem rápido usando-se o SET INDEX MEMORY ADDITIVE mas o problema persiste na hora da atualização dos campos de cada registro filtrado.

Um REPLACE ALL semelhante ao UPDATE no sql parace que o programa travou rsrs

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 13 Dez 2019 13:33
por JoséQuintas
Mas 500.000 cartelas de bingo.... se for 1 real cada... isso dá meio milhão de reais.

Tem outra coisa:

Se o processamento for no terminal, a quantidade de cartelas vai ser pequena.
Se o processamento for no servidor... aí precisa demorar menos do que o sorteio de cada bola.
Se o servidor pegar o resultado pronto dos terminais, vai ter menos processamento, porque fica tudo distribuído.

E mais outra: sei lá como fazer em multithread, mas....

Se houver um processo fazendo em ordem das que faltam menos... o resultado, que é o mais importante, estaria pronto antes do processo completo terminar, e nem notariam a demora do processo restante.

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 13 Dez 2019 13:39
por JoséQuintas
Não sei também se ir limpando o array agiliza, pra ter menos números pra processar....
Sempre daria pra pesquisar os números completos pelo número da cartela, então deixa de ser importante trabalhar sempre com todos os números.
Só não sei se o tempo do hb_ADel() vai compensar o ganho de tempo. (no caso de array), ou o tempo de limpar a string no DBF (numero $ trim( falta ) ).

Vai ter que fazer os testes.

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 13 Dez 2019 13:44
por JoséQuintas
Também vários arrays...

Um array para as cartelas que faltam 1 número, outro pra 2, etc. e transferindo de um para o outro.

Imagino assim:
sorteou uma bola.... o urgente é analisar os que só faltavam 1 bola, os demais não tem pressa.
as cartelas que faltam 2 números nunca vão fazer bingo antes das que faltam 1 só número...
As demais... sem pressa de trazer o resultado.

Acho que vai ser impossível as 500.000 cartelas esperando um único número....
Se forem distribuídos de forma igual, poderia reduzir em 100 vezes.... 5.000 cartelas esperando um único número.

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 13 Dez 2019 14:13
por JoséQuintas
Acho que estou a 1000 por hora hoje.... kkkk
Pensei num trem doido pra última opção:

Código: Selecionar todos

PROCEDURE Main

   LOCAL aList := {}
   
   FOR EACH aFalta IN aList DESC
      FOR EACH aNumeros IN aFalta DESC
         lAcertou := .F.
         FOR EACH nNumero IN aNumeros
            IF nNumero:__EnumIndex != 1
               IF nNumero == nSorteio
                  hb_Adel( aNumeros, nNumero:__EnumIndex, .T. )
                  lAcertou := .T.
                  EXIT
               ENDIF
            ENDIF
         NEXT
         IF lAcertou
            AAdd( aFalta[ aFalta:_EnumIndex - 1 ], aNumeros )
            hb_ADel( aFalta[ aFalta:_EnumIndex ], .T. )
         ENDIF
      NEXT   
      IF aFalta:__EnumIndex < 2 .AND. Len( aFalta[ 1 ] ) != 0
         // alguém ganhou
      ENDIF
   NEXT

   RETURN
É um array geral, com um array pra cada quantidade faltante.
Cada array interno vai ter o número da cartela, e os números que faltam, por isso pula o 1 na checagem de números
Cada número acertado retira o número da lista da cartela, e move a cartela pro array "anterior"
O array 1 seria dos que fizeram bingo, então... assim que processa o array 2 dos que estão pra bater, se existir elemento no array 1 já indica que alguém bateu.

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 13 Dez 2019 14:19
por JoséQuintas
E nem precisa se preocupar com array ZERO....
Quem já acertou todos os números... não vai acertar mais nenhum.... então nunca vai mover do 1 pro ZERO.

O sorteio das primeiras bolas vai ser o mais demorado, mas vai agilizando a cada bola sorteada, porque vão ser menos números pra fazer teste.

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 13 Dez 2019 14:26
por JoséQuintas
Outra idéia pro SQL: ter 100 campos com S ou N, um pra cada número, e índices também para os 100 campos, para o falta, e para o número da cartela

UPDATE TABELA SET FALTA = FALTA - 1, NUMERO10='X' WHERE NUMERO10 = 'S'
SELECT * FROM TABELA WHERE FALTA = 0

Desta forma, o SELECT e o UPDATE vão ser em 5.000 cartelas, e não nas 500.000

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 13 Dez 2019 15:22
por Ladinilson Sousa
José Quintas

Fiz um estudo e a solução foi simples até depois de procurar sintaxes e sintaxes.

"As vezes o menos é mais!"

Código: Selecionar todos

    PRIVATE aCartelas := {" "," "," "}

    SELECT Cartelas
    Cartelas->(DBGOTOP())   
    DbEVal({||AADD(aCartelas,{ALLTRIM(STR(Cartelas->numero)),Cartelas->seqcar,STRZERO(Cartelas->falta,2)})}) 
    Cartelas->(DBGOTOP())

   FOR s := 1 TO LEN(aCartelas)
         n:= aCartelas[s][1]
         q:= aCartelas[s][2]
         f:= VAL(aCartelas[s][3])
        IF AT(STRZERO(Bolanumero,2),q) > 0
            f := VAL(f)-1
            aCartelas[s][3] := STRZERO(f,2)
       ENDIF 
       IF f < vnFalta 
   	    carma++
       ENDIF	 
	IF f == 0
	    vbateu := .t.
	    SELECT Cartelas
	    Cartelas->(DBGOTOP())
	    Cartelas->(ORDSETFOCUS("numero"))
	    Cartelas->(DBGOTOP())
	    SEEK n
           Cartelas->sorteou := nPremio 
           Cartelas->falta   := f
     ENDIF   
    NEXT    

Velha e simples sintaxe mas funcional rsrsr

Bom final de semana para senhor!

Obrigado

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 13 Dez 2019 15:41
por JoséQuintas
se desse jeito já resolveu, pode deixar mais básico/rápido ainda e retirar os StrZero() e o At()
Os gotop são inúteis, poderia retirar também.

O at() pode ser substituído por if "texto" $ string

Trabalhando com ARRAY em vez de DBFCDX

Enviado: 17 Dez 2019 22:44
por Nascimento
achei um link que pode ser util
https://www.linguagemclipper.com.br/dicas/arrays