Re: Motor de batallas, código fuente (muy técnico me temo)
Publicado: 06 Ene 2011 20:12
que me banees YA!!Andurino escribió:QUE PARTE DE VOSOTROS ME ESTAIS FALTADO NO ENTIENDES.
QUE ME BANEES YA!!
Otro clónico del jueguito ese de naves
http://www.ogarena.es/foro/
que me banees YA!!Andurino escribió:QUE PARTE DE VOSOTROS ME ESTAIS FALTADO NO ENTIENDES.
QUE ME BANEES YA!!
Que parte de que me banees ya no entiendes. EnteradoAndurino escribió:que me banees YA!!Andurino escribió:QUE PARTE DE VOSOTROS ME ESTAIS FALTADO NO ENTIENDES.
QUE ME BANEES YA!!
Veo que nos has puesto todo el codigo (facil de traducir a otros lenguajes), pero no has dado ninguna descripción de las estructuras de datos que usa el motor de batallas. Con esa estructura, podría usar una traducción del codigo adaptada a los datos de un formulario de simulacion, creando un programa offline que simule combates.asturcon3 escribió:Siempre que sale el tema de hacer un simulador y yo respondo que paso mucho de mantener un programa para eso, saltan uno o varios que dicen que si tuvieran el algoritmo de las batallas podrían hacerlo. Bueno, vamos a verlo.
Primero, culturilla. El motor de batallas actual es un proyecto de Visual C++ que genera un ejecutable con un diálogo donde lo único útil que hay es un cuadro de texto grande donde se va mostrando lo que hace el programa (un log). Hay un timer, que cuando se pasa el tiempo comprueba si hay una batalla pendiente de ejecutar. Si no la hay, reprograma el timer a un número fijo de segundos o a lo que queda hasta la siguiente flota (el menor de ambos). Si hay batalla, el programa recupera de la base de datos una cadena tocha que contiene, separados por caracteres |, todos los elementos que intervienen en la batalla.
Con esa cadena, dividiéndola, genera su propia representación interna de la batalla y la ejecuta. Cuando acaba, y basándose en esa misma representación interna, genera llamadas a la base de datos para computar el robo, la creación de luna, y los reportes de batalla.
Bueno, pues voy a publicar aquí la parte del timer (una rutina en el diálogo) y la clase Motor.cpp que realiza toda la batalla. En principio creo que cualquier programador que realmente pretenda hacer un simulador debería tener más que suficiente con eso. Pero si no es así, comentádmelo.
A ver, el timer del diálogo:Sintaxis de la cadena que toma como entrada:Oculto:Código: Seleccionar todo
void CogArenaMonitorDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Agregue aquí su código de controlador de mensajes o llame al valor predeterminado KillTimer(m_nTimer); while (1) { CString tS,tId; #ifdef _DEBUG if (0) { tS="BATALLA|460|[4:48:12]|6090925| 000.00| 000.30|0|100000|0|-|A|827|CaPRiCoRN|217902|[4:47:18]|24|23|24|F|6090925|206|5425709|1360|165|9180|213|2043025|6800|1650|37400||D|92|asturcon3|460|[4:48:12]|25|22|24|P|460|202|4699776|18|32|1360|203|2125067|18|80|4080|206|301|1400|160|9180|207|16|3500|640|20400|208|14000|175|320|10200|209|1003|4|32|5440|210|1499834|0|3|340|214|1|700000|160000|3060000|221|1|35000000|32000000|1|401|691444|280|64|680|402|1939217|350|80|680|403|4527|875|320|2720|404|902|3850|640|11900|405|450|525|1600|2720|406|49242|10500|960|34000|407|1|4|6400|6800|408|1|4|32000|34000|"; } else #endif { while (_T("ERROR") == (tId=theApp.callDelay())) { log(_T("reconectar")); conectar(); } int segs=_ttoi(tId); if (segs>=0) { log(_T(".")); m_nTimer=SetTimer(0,segs*(long)1000+1,NULL); return; } time_t osBinaryTime; // C run-time time (defined in <time.h>) time( &osBinaryTime ); CTime ahora(osBinaryTime); tId=tId.Mid(1); tS.Format(_T("idF=%s %s\r\n"),tId,ahora.Format("%d/%m %H:%M:%S")); log(tS); tS=theApp.callFlotaEvent(tId); // tS=theApp.callProcP(_T("flotaEvent"),tId); } if (tS.Left(8)=="BATALLA|") { log(tS.Trim()); m_motor.batallar(tS); } } }
El código principal de motor4.cpp (no me deja adjuntarlo como tal, asíq ue copio y pego)Oculto:(| es el separador, lo de (...)+ que hay en cada flota indica que lo de dentro de los paréntesis se repite tantas veces como tipos de naves haya)Como comentario, en la flota defensora se pasan también las defensas, del mismo modo (código de tipo, número, tecnos)Código: Seleccionar todo
BATALLA|códigoDePlanetaVíctima|Coordenadas|idFlotaQueLlega|IndicadorDeDefensaAEscombros(0/1)|PorcentajeEscombros|SePodríaCrearLunaAqui(0/1)|EscombrosPara1%luna|-| Flota1: Bando(A de Atacante,D de Defensor)|idJugador|nick|planetaBase|coordenadas|tecno1|tecno2|tecno3|tipoId(F de Flota,P de Planeta)|idFlota/Planeta| (tipoNave|numDeNaves|Ataque|Defensa|Blindaje|)+| Flota 2:... ...
Y ya por fin, en todas partes del juego los elementos (edificios, naves, defensas, tecnos, objetos) se identifican con un código numérico, habitualmente llamado gid (GraphicID, supongo), se ve perfectamente en el juego al picar el nombre de una nave para ver su descripción)Mmmm ¿qué me queda?Oculto:Código: Seleccionar todo
// Motor4.cpp: archivo de implementación // #include "stdafx.h" #include "ogArenaMonitor.h" #include "Motor4.h" // CMotor CMotor4::CMotor4() { } CMotor4::~CMotor4() { if (m_pFuegoRapido) { for (int i=0;i<300;i++) if (m_pFuegoRapido[i]) free(m_pFuegoRapido[i]); free(m_pFuegoRapido); } if (m_costes) free(m_costes); } int orden4(const void *na, const void *nb) { const TNave *a,*b; a=(const TNave *)na; b=(const TNave *)nb; if (!a->nGrupo) return b->nGrupo ? 1:0; if (a->rondaMuerta!=b->rondaMuerta) return (a->rondaMuerta > b->rondaMuerta) ? -1:1; if (a->capturada!=b->capturada) return (a->capturada<b->capturada) ? -1:1; if (a->blindaje!=b->blindaje) return (a->blindaje<b->blindaje) ? -1:1; if (a->escudo!=b->escudo) return (a->escudo<b->escudo) ? -1:1; return 0; } int ordenIndice(const void *na, const void *nb) { const TIndiceGrupos *a,*b; a=(const TIndiceGrupos *)na; b=(const TIndiceGrupos *)nb; if (a->capturada!=b->capturada) return (a->capturada<b->capturada) ? -1:1; if (a->blindaje!=b->blindaje) return (a->blindaje<b->blindaje) ? -1:1; if (a->escudo!=b->escudo) return (a->escudo<b->escudo) ? -1:1; return 0; } int checkIndex(TIndiceGrupos *base,int nGrupos,TNave *grupos) { #ifdef _DEBUG int i; TNave *n; for (i=0;i<nGrupos;i++) { if (i) ASSERT(ordenIndice(base+i-1,base+i)<=0); ASSERT(base[i].grupo>=0); // ASSERT(base[i].grupo<nGrupos); -- No es correcto, no se trata del mismo contador n=grupos+base[i].grupo; if (base[i].capturada!=-1) { // Flag grupo muerto antes ASSERT( n->escudo==base[i].escudo); ASSERT( n->blindaje==base[i].blindaje); ASSERT( n->capturada==base[i].capturada); } } return 1; #else return 1; #endif } int buscaIndiceGrupos(TIndiceGrupos *base,int nGrupos,int capturada,int escudo,int blindaje,int buscar,int numGrupo=-1) { TIndiceGrupos test; int inf,sup,centro,comp; TIndiceGrupos *p; test.capturada=capturada; test.escudo=escudo; test.blindaje=blindaje; inf=0; sup=nGrupos-1; while (inf<=sup) { centro=(inf+sup)/2; p=&base[centro]; comp=ordenIndice(&test,p); if (!comp) { // Encontrado valor if (numGrupo==-1) return centro; inf=centro; // si se busca grupo concreto buscar atras y alante while (true) { if (base[inf].grupo==numGrupo) return inf; if (!inf) break; inf--; if (ordenIndice(&test,&base[inf])) break; } sup=centro; while (true) { sup++; if (sup>=nGrupos) break; if (ordenIndice(&test,&base[sup])) break; if (base[sup].grupo==numGrupo) return sup; } return -1; } if (comp<0) sup=centro-1; else inf=centro+1; } if (buscar==0) return -1; if (comp<0) return centro; // test es menor que centro, almacenar en centro return centro+1; // test es mayor que centro, devolver siguiente } void moveIndex(TIndiceGrupos *base,int nGrupos,int lPos,int newPos) { TIndiceGrupos t; ASSERT(lPos>=0); ASSERT(newPos>=0); if (lPos==newPos) return; memcpy(&t,base+lPos,sizeof(TIndiceGrupos)); if (newPos>lPos) { memcpy(base+lPos,base+lPos+1,sizeof(TIndiceGrupos)*(newPos-lPos)); } else if (newPos<lPos) { memcpy(base+newPos+1,base+newPos,sizeof(TIndiceGrupos)*(lPos-newPos)); } memcpy(base+newPos,&t,sizeof(TIndiceGrupos)); } void CMotor4::batallar(CString &txt) { CString reporte,tS; int i,j,iFlota,iLin,m,n,nToks,gid,bando,nFlotas; __int64 navesA,navesD; int soloSondas=1,numSondasA=0,bEstampadaSondas=0; // Comprobacion rápida solosondas && numFR>numSondas->muerte directa __int64 numFRASondas=0; int talismanes; __int64 escombros1pc; DWORD inicio,fin; unsigned int seed; inicio=GetTickCount(); seed=(unsigned int)inicio; tS.Format("srand(%u)",seed); log(tS); srand(seed); #ifdef _DEBUG srand(44505125); #endif m_perdidas[0]=0; m_perdidas[1]=0; m_escombros[0] =m_escombros[1]=0; CString *toks=split("|",txt,n); ASSERT(n>6); CString batCP=toks[1]; CString batCoords=toks[2]; int idF=atoi(toks[3]); m_defEscombros=atof(toks[4]); m_porcEscombros=atof(toks[5]); int lunable=atoi(toks[6]); escombros1pc=_atoi64(toks[7]); if (n>8) talismanes=atoi(toks[8]); else talismanes=0; delete []toks; toks=split("|-|",txt,n); CString t=toks[1]; delete []toks; CString *flotaStr=split("||",t,nFlotas); m_flotas[0]=new TFlotas[nFlotas]; m_flotas[1]=new TFlotas[nFlotas]; time_t ahora; time(&ahora); reporte.Format("%li",ahora); m_totNaves=0; navesA=navesD=0; m_nFlotas[0]=m_nFlotas[1]=0; // comprobar muerte de sondas for (iFlota=0;iFlota<nFlotas;iFlota++) { toks=split("|",flotaStr[iFlota],nToks); bando=toks[0]=='A' ? 0:1; for (n=10;n<nToks-3;n+=5) { j=atoi(toks[n]); // gid i=atoi(toks[n+1]); // cant if (!bando) { if (j!=210) soloSondas=0; else numSondasA+=i; } if (!soloSondas) break; if (bando) { if (m_pFuegoRapido[j-200]) numFRASondas+=(__int64)i*m_pFuegoRapido[j-200][210-200]; } } delete []toks; } bEstampadaSondas=soloSondas && numFRASondas>numSondasA; // Crear flotas y grupos de naves for (iFlota=0;iFlota<nFlotas;iFlota++) { toks=split("|",flotaStr[iFlota],nToks); bando=toks[0]=='A' ? 0:1; for (n=10;n<nToks-3;n+=5) { i=atoi(toks[n+1]); m_totNaves+=i; if (!bando) navesA+=i; else navesD+=i; } delete []toks; } m_batDivisor=1; while (m_totNaves>10000000 && navesA>100000 && navesD>100000) { m_batDivisor*=2; m_totNaves/=2; navesA/=2; navesD/=2; } m_totNaves=0; navesA=0; navesD=0; for (iFlota=0;iFlota<nFlotas;iFlota++) { toks=split("|",flotaStr[iFlota],nToks); bando=toks[0]=='A' ? 0:1; i=m_nFlotas[bando]; m_flotas[bando][i].idJug=atoi(toks[1]); m_flotas[bando][i].nick=toks[2]; m_flotas[bando][i].CP=atoi(toks[3]); m_flotas[bando][i].coords=toks[4]; m_flotas[bando][i].tipoIdPlan=toks[8][0]; m_flotas[bando][i].idJuego=atoi(toks[9]); // m_flotas[bando][i].ataques=(int *)calloc(500,sizeof(int)); // m_flotas[bando][i].maxEscudos =(int *)calloc(500,sizeof(int)); // m_flotas[bando][i].maxBlind=(int *)calloc(500,sizeof(int)); // m_flotas[bando][i].tocadas=(TTocadas **)calloc(500,sizeof(TTocadas*)); m_flotas[bando][i].capturas=(int *)calloc(500,sizeof(int)); m_flotas[bando][i].vCapturas=m_flotas[bando][i].vPerdidas=0; // m_flotas[bando][i].blindajeIntacto=(int *)calloc(500,sizeof(int)); m_flotas[bando][i].lineas=(TLinea *)calloc(50,sizeof(TLinea)); m_flotas[bando][i].nLineas=0; m_flotas[bando][i].ataques=(int *)calloc(500,sizeof(int)); m_flotas[bando][i].escudos=(int *)calloc(500,sizeof(int)); m_flotas[bando][i].blindajes=(int *)calloc(500,sizeof(int)); for (n=10,iLin=0;n<nToks-3;n+=5,iLin++) { // t.Format("Flota %i %s %s*%s",iFlota,toks[0],toks[n],toks[n+1]); // log(t); gid=atoi(toks[n]); m_flotas[bando][i].lineas[iLin].gid=gid; m_flotas[bando][i].ataques[gid]=m_flotas[bando][i].lineas[iLin].ataques=atoi(toks[n+2]); m_flotas[bando][i].escudos[gid]=m_flotas[bando][i].lineas[iLin].maxEscudo=atoi(toks[n+3]); m_flotas[bando][i].blindajes[gid]=m_flotas[bando][i].lineas[iLin].maxBlindaje=atoi(toks[n+4]); m=atoi(toks[n+1]); m_flotas[bando][i].lineas[iLin].nGrupoOrig=m; m=m/m_batDivisor; if (!m) m=1; m_totNaves+=m; if (!bando) navesA+=m; else navesD+=m; m_flotas[bando][i].lineas[iLin].nGrupo=m_flotas[bando][i].lineas[iLin].nGrupoOrigDiv=m; if (m<5000000 && !bEstampadaSondas) { // Lineal m_flotas[bando][i].lineas[iLin].maxGrupos=-1; m_flotas[bando][i].lineas[iLin].grupos=(TNave *)calloc(m ? m:1,sizeof(TNave)); m_flotas[bando][i].lineas[iLin].grupos[0].nGrupo=1; m_flotas[bando][i].lineas[iLin].grupos[0].blindaje=m_flotas[bando][i].lineas[iLin].maxBlindaje; for (j=1;j<m;j++) memcpy(&m_flotas[bando][i].lineas[iLin].grupos[j],&m_flotas[bando][i].lineas[iLin].grupos[0],sizeof(TNave)); m_flotas[bando][i].lineas[iLin].nGrupos=m; } else { // Agrupado m_flotas[bando][i].lineas[iLin].maxGrupos=100; m_flotas[bando][i].lineas[iLin].grupos=(TNave *)calloc(100,sizeof(TNave)); m_flotas[bando][i].lineas[iLin].grupos[0].nGrupo=m_flotas[bando][i].lineas[iLin].nGrupo; m_flotas[bando][i].lineas[iLin].grupos[0].blindaje=m_flotas[bando][i].lineas[iLin].maxBlindaje; m_flotas[bando][i].lineas[iLin].nGrupos=1; if (!bando && bEstampadaSondas) m_flotas[bando][i].lineas[iLin].grupos[0].blindaje=-1,m_flotas[bando][i].lineas[iLin].grupos[0].rondaMuerta=1; } } m_flotas[bando][i].nLineas=iLin; m_nFlotas[bando]++; reporte+="/"+toks[0]; for (n=2;n<=7;n++) reporte+="/"+toks[n]; delete []toks; } delete []flotaStr; int ganador=0,ronda=1; int bAtaque=0; if (bEstampadaSondas) ganador=2,ronda=2; // fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("IniRondas"),(fin-inicio)/1000.0); log(t); for (;ronda<=7 && !ganador;ronda++) { TNave *iNave; //t.Format("Ronda %i ",ronda); // log(t); m_navBandos[0]=m_navBandos[1]=0; for (bando=0;bando<=1;bando++) { for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) { for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) { m_flotas[bando][iFlota].lineas[iLin].nGrupo=0; if (ronda==1) m_flotas[bando][iFlota].lineas[iLin].nav2grupos=NULL; } } } bAtaque=0; // maxEscudos+comprobar ataque for (bando=0;bando<=1;bando++) { for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) { for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) { if (m_flotas[bando][iFlota].lineas[iLin].maxGrupos==-1) { // Lineal iNave=m_flotas[bando][iFlota].lineas[iLin].grupos; n=m_flotas[bando][iFlota].lineas[iLin].maxEscudo; m=0; for (i=m_flotas[bando][iFlota].lineas[iLin].nGrupos;i;i--,iNave++) { if (iNave->blindaje>=0) { iNave->escudo=n; m++; } else { if (!iNave->rondaMuerta) iNave->rondaMuerta=ronda-1; } } m_flotas[bando][iFlota].lineas[iLin].nGrupo=m; m_navBandos[bando]+=m; if (!bAtaque && !bando && m) bAtaque=m_flotas[bando][iFlota].lineas[iLin].ataques; } else { if (m_flotas[bando][iFlota].lineas[iLin].nav2grupos) { free(m_flotas[bando][iFlota].lineas[iLin].nav2grupos); m_flotas[bando][iFlota].lineas[iLin].nav2grupos=NULL; } for (i=0;i<m_flotas[bando][iFlota].lineas[iLin].nGrupos;i++) { iNave=&m_flotas[bando][iFlota].lineas[iLin].grupos[i]; if (iNave->blindaje>=0) { iNave->escudo=m_flotas[bando][iFlota].lineas[iLin].maxEscudo; m_flotas[bando][iFlota].lineas[iLin].nGrupo+=iNave->nGrupo; m_navBandos[bando]+=iNave->nGrupo; if (!bAtaque && !bando) bAtaque=m_flotas[bando][iFlota].lineas[iLin].ataques; } else { if (!iNave->rondaMuerta) iNave->rondaMuerta=ronda-1; } } qsort(&m_flotas[bando][iFlota].lineas[iLin].grupos[0],m_flotas[bando][iFlota].lineas[iLin].nGrupos,sizeof(TNave),orden4); for (n=0,i=1;i<m_flotas[bando][iFlota].lineas[iLin].nGrupos;i++) { if (m_flotas[bando][iFlota].lineas[iLin].grupos[i].nGrupo) { if (!m_flotas[bando][iFlota].lineas[iLin].grupos[i].rondaMuerta && !m_flotas[bando][iFlota].lineas[iLin].grupos[n].rondaMuerta && m_flotas[bando][iFlota].lineas[iLin].grupos[i].capturada==m_flotas[bando][iFlota].lineas[iLin].grupos[n].capturada && m_flotas[bando][iFlota].lineas[iLin].grupos[i].blindaje==m_flotas[bando][iFlota].lineas[iLin].grupos[n].blindaje) { m_flotas[bando][iFlota].lineas[iLin].grupos[n].nGrupo+=m_flotas[bando][iFlota].lineas[iLin].grupos[i].nGrupo; m_flotas[bando][iFlota].lineas[iLin].grupos[i].nGrupo=0; } else { n++; if (i!=n) memcpy(&m_flotas[bando][iFlota].lineas[iLin].grupos[n],&m_flotas[bando][iFlota].lineas[iLin].grupos[i],sizeof(TNave)); } } } m_flotas[bando][iFlota].lineas[iLin].nGrupos=n+1; } } } } if (!m_navBandos[0]) ganador=2; else if (!m_navBandos[1] && bAtaque) ganador=1; if (ganador) break; if (ronda==7) break; if (!batDispara(ronda)) break; // fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Disparos"),(fin-inicio)/1000.0); log(t); if (bAtaque==0 && m_navBandos[1]==0) break; // Empate si nada contra nada, despues de batDispara para q saque disparos en reporte } //t.Format("Fin de batalla, rondas=%i, atacantes=%i, defensores=%i\r\n",ronda,m_navBandos[0],m_navBandos[1]); // log(t); for (bando=0; bando<=1; bando++) for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) navesMuertas(bando,iFlota); // fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Muertas"),(fin-inicio)/1000.0); log(t); for (i=1;i<=ronda;i++) { t.Format("/%i",i); reporte+=t; for (bando=0;bando<=1;bando++) for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) reporte+="/"+battFl(bando,iFlota,i==1,i); if ((ganador && i==ronda) || i==7) break; for (n=0;n<2;n++) { t.Format("/%s/%I64i/%I64i/%I64i",n ? "DD":"DA",m_rondas[i].disparos[n],m_rondas[i].fuerza[n],m_rondas[i].absor[n]); reporte+=t; } } i=reporte.GetLength(); t.Format("/F/%i",ganador); reporte+=t; // fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Info1"),(fin-inicio)/1000.0); log(t); if (ganador==1) { // Robo t.Format("%i",idF); t=theApp.callRobo(t); toks=split("|",t,n); reporte+="/R"; for (i=0;i<n;i++) reporte+="/"+toks[i]; delete []toks; } t.Format("/PA/%I64i",m_perdidas[0]); reporte+=t; t.Format("/PD/%I64i",m_perdidas[1]); reporte+=t; t.Format("/ES/%I64i/%I64i",m_escombros[0],m_escombros[1]); reporte+=t; __int64 esc=m_escombros[0] +m_escombros[1]; int diamLuna=0,porcLuna; if (lunable && esc>=escombros1pc) { if (esc>20*escombros1pc) porcLuna=20; else porcLuna=(int)(esc/escombros1pc); porcLuna=porcLuna > 20 ? 20:porcLuna; t.Format("/L/%i",porcLuna); reporte+=t; // Check creacion luna do { if ((rand()*1.0/RAND_MAX)<porcLuna/100.0) { reporte+="/NL"; diamLuna=400*porcLuna; break; } } while (talismanes--); } // fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Info2"),(fin-inicio)/1000.0); log(t); if (reporte.GetLength()>1024) { theApp.callProc("reporteIni","","reporteIni"); for (i=0;i<reporte.GetLength();i+=1024) theApp.callProc("reporteAdd","'"+reporte.Mid(i,1024)+"'","reporteAdd"); reporte="REPORTE"; } t.Format("%i,%i,'%s',%I64i,%I64i,%I64i,%I64i,%i,%i", idF,ganador,reporte,m_escombros[0],m_escombros[1],m_perdidas[0],m_perdidas[1],diamLuna,ronda); theApp.callProc("eg_FinBatalla",t,"eg_FinBatalla"); // fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Fin"),(fin-inicio)/1000.0); log(t); log("Finalizado\r\n"); for (bando=0;bando<2;bando++) { for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) { for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) { delete []m_flotas[bando][iFlota].lineas[iLin].grupos; } delete []m_flotas[bando][iFlota].capturas; delete []m_flotas[bando][iFlota].lineas; delete []m_flotas[bando][iFlota].ataques; delete []m_flotas[bando][iFlota].escudos; delete []m_flotas[bando][iFlota].blindajes; } delete []m_flotas[bando]; } fin=GetTickCount(); t.Format(_T("'Batalla',%f"),(fin-inicio)/1000.0); theApp.callProc("cronoIns",t,"cronos"); log(t); } CString CMotor4::battFl(int bando,int iFlota,bool bExtraInfo,int ronda) { int *gids=(int *)calloc(600,sizeof(int)); int *tot=(int *)calloc(600,sizeof(int)); int *nGrupo=(int *)calloc(600,sizeof(int)); int *nOrig=(int *)calloc(600,sizeof(int)); int nNave,i,iLin; for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) { nGrupo[m_flotas[bando][iFlota].lineas[iLin].gid]+=m_flotas[bando][iFlota].lineas[iLin].nGrupoOrigDiv; nOrig[m_flotas[bando][iFlota].lineas[iLin].gid]+=m_flotas[bando][iFlota].lineas[iLin].nGrupoOrig; for (nNave=0;nNave<m_flotas[bando][iFlota].lineas[iLin].nGrupos;nNave++) { TNave *iNave=&m_flotas[bando][iFlota].lineas[iLin].grupos[nNave]; if (bExtraInfo) { if (iNave->rondaMuerta) tot[m_flotas[bando][iFlota].lineas[iLin].gid]+=iNave->nGrupo; } if (!iNave->rondaMuerta || iNave->rondaMuerta>=ronda) gids[m_flotas[bando][iFlota].lineas[iLin].gid]+=iNave->nGrupo; } } if (m_batDivisor>1) { for (i=0;i<600;i++) { if (nOrig[i]) { if (tot[i]==nGrupo[i]) tot[i]=nOrig[i]; else tot[i]*=m_batDivisor; if (gids[i]==nGrupo[i]) gids[i]=nOrig[i]; else gids[i]*=m_batDivisor; } } } CString ret,t; for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",i); ret+=t; } if (ret=="") { ret="0"; } else { ret+="/"; for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",gids[i]); ret+=t; } ret+="/"; if (bExtraInfo) { for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",m_flotas[bando][iFlota].ataques[i]); ret+=t; } ret+="/"; for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",m_flotas[bando][iFlota].escudos[i]); ret+=t; } ret+="/"; for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",m_flotas[bando][iFlota].blindajes[i]); ret+=t; } ret+="/"; for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",tot[i]); ret+=t; } ret+="/"; if (m_flotas[bando][iFlota].vPerdidas) { t.Format("P/%I64i/",m_flotas[bando][iFlota].vPerdidas); ret+=t; } if (m_flotas[bando][iFlota].vCapturas) { t.Format("C/%I64i/",m_flotas[bando][iFlota].vCapturas); ret+=t; } } } free(gids); free(tot); return ret; } void CMotor4::init(void) { CRecordset r(&theApp.m_db); CDBVariant v; m_pFuegoRapido=(int **)calloc(300,sizeof(int *)); for (int i=0;i<300;i++) m_pFuegoRapido[i]=NULL; r.Open(-1,_T("select * from fuegoRapido")); while (!r.IsEOF()) { // r.GetFieldValue((short)0,v); r.GetFieldValue((short)0,v,SQL_C_SLONG); int gidA=v.m_iVal; if (!m_pFuegoRapido[gidA-200]) m_pFuegoRapido[gidA-200]=(int *)calloc(300,sizeof(int)); r.GetFieldValue(1,v,SQL_C_SLONG); int gidD=v.m_iVal; r.GetFieldValue(2,v,SQL_C_SLONG); int n=v.m_iVal; m_pFuegoRapido[gidA-200][gidD-200]=n; r.MoveNext(); } r.Close(); log(_T("Cargados fuegos rápidos\r\n")); m_costes=(TCoste *)calloc(300,sizeof(TCoste)); r.Open(-1,_T("select gid,costeM_gid,costeC_gid,costeD_gid from gids where gid between 200 and 499")); while (!r.IsEOF()) { r.GetFieldValue((short)0,v,SQL_C_SLONG); int gid=v.m_iVal; r.GetFieldValue(1,v,SQL_C_SLONG); m_costes[gid-200].costeM=v.m_lVal; r.GetFieldValue(2,v,SQL_C_SLONG); m_costes[gid-200].costeC=v.m_lVal; r.GetFieldValue(3,v,SQL_C_SLONG); m_costes[gid-200].costeD=v.m_lVal; r.MoveNext(); } r.Close(); log(_T("Cargados costes\r\n")); } void CMotor4::log(CString txt) { theApp.log(txt); } void CMotor4::navesMuertas(int bando,int iFlota) { int *muertas=(int *)calloc(600,sizeof(int)); int *capturadas=(int *)calloc(600,sizeof(int)); int *grupo=(int *)calloc(600,sizeof(int)); int *reales=(int *)calloc(600,sizeof(int)); int nNave,iLin,gid,i; __int64 n,muertasi,nPerd; for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) { for (nNave=0;nNave<m_flotas[bando][iFlota].lineas[iLin].nGrupos;nNave++) { gid=m_flotas[bando][iFlota].lineas[iLin].gid; TNave *iNave=&m_flotas[bando][iFlota].lineas[iLin].grupos[nNave]; if (iNave->rondaMuerta) { if (iNave->capturada) capturadas[gid]+=iNave->nGrupo; else muertas[gid]+=iNave->nGrupo; } } grupo[gid]+=m_flotas[bando][iFlota].lineas[iLin].nGrupoOrigDiv; reales[gid]+=m_flotas[bando][iFlota].lineas[iLin].nGrupoOrig; } CString ret,t,sql; for (i=0;i<600;i++) { if (muertas[i]+capturadas[i]) { n=(__int64)(muertas[i]+capturadas[i]); muertasi=(__int64)muertas[i]; if (m_batDivisor>1) { if (n==grupo[i]) n=reales[i]; else n*=m_batDivisor; if (muertasi==grupo[i]) muertasi=reales[i]; else muertasi*=m_batDivisor; } nPerd=n*(m_costes[i-200].costeM+m_costes[i-200].costeC+m_costes[i-200].costeD); m_perdidas[bando]+=nPerd; m_flotas[bando][iFlota].vPerdidas+=nPerd; if (i<400) { m_escombros[0]+=(__int64)(muertasi*(m_costes[i-200].costeM*m_porcEscombros)); m_escombros[1]+=(__int64)(muertasi*(m_costes[i-200].costeC*m_porcEscombros)); } else { m_escombros[0]+=(__int64)(muertasi*(m_costes[i-200].costeM*m_defEscombros)); m_escombros[1]+=(__int64)(muertasi*(m_costes[i-200].costeC*m_defEscombros)); } sql.Format("'%c',%i,%i,%i", m_flotas[bando][iFlota].tipoIdPlan,m_flotas[bando][iFlota].idJuego,i,n); theApp.callProc("eg_FinBatFl",sql,"FinBatFl"); } } for (i=0;i<500;i++) { if(n=m_flotas[bando][iFlota].capturas[i]) { if (m_batDivisor>1) { if (n==grupo[i]) n=reales[i]; else n*=m_batDivisor; } sql.Format("'%c',%i,%i,%i", m_flotas[bando][iFlota].tipoIdPlan,m_flotas[bando][iFlota].idJuego,i,-n); m_flotas[bando][iFlota].vCapturas+=(__int64)(n*(m_costes[i-200].costeM+m_costes[i-200].costeC+m_costes[i-200].costeD)); theApp.callProc("eg_FinBatFl",sql,"FinCapturas"); } } sql.Format("'%c',%i,%i,%i", m_flotas[bando][iFlota].tipoIdPlan,m_flotas[bando][iFlota].idJuego,-1,0); theApp.callProc("eg_FinBatFl",sql,"FinCapturas"); free(muertas); free(capturadas); free(grupo); free(reales); } int CMotor4::fuegoRapido(int gidA,int gidD) { if (!m_pFuegoRapido[gidA-200]) return 0; int n=m_pFuegoRapido[gidA-200][gidD-200]; if (!n) return 0; if (!(rand()%n)) { return 0; } return 1; } int CMotor4::almacenar(TLinea * pvLinea,TNave *vNave,int iGrV,int iVict, int escudo,int blinda,unsigned __int8 capturada) { int iH,vAGrupo,n,m; TIndiceGrupos *pig; TNave * tNave; if (vNave->blindaje<0) { // Ya estaba muerta de antes ; } else { if (pvLinea->maxGrupos==-1) { // Array lineal vNave->blindaje=blinda; vNave->escudo=escudo; vNave->capturada=capturada; } else { iH=-1; vAGrupo=-1; if (vNave->nGrupo==1) { n=-1; if (pig=pvLinea->indiceGrupos) { n=buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,vNave->capturada,vNave->escudo,vNave->blindaje,0,iGrV); ASSERT(pvLinea->grupos[pig[n].grupo].blindaje==vNave->blindaje); ASSERT(pvLinea->grupos[pig[n].grupo].escudo==vNave->escudo); ASSERT(pvLinea->grupos[pig[n].grupo].capturada==vNave->capturada); DEBUG_ONLY(checkIndex(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,pvLinea->grupos)); } vNave->blindaje=blinda; vNave->escudo=escudo; vNave->capturada=capturada; if (n!=-1) { m=buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,vNave->capturada,vNave->escudo,vNave->blindaje,-1); pig[n].blindaje=blinda; pig[n].capturada=capturada; pig[n].escudo=escudo; moveIndex(pvLinea->indiceGrupos,pvLinea->nGrupos,n,m); DEBUG_ONLY(checkIndex(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,pvLinea->grupos)); } } else { if (pvLinea->indiceGrupos) { vAGrupo=buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,capturada,escudo,blinda,0); if (vAGrupo!=-1) { vAGrupo=pvLinea->indiceGrupos[vAGrupo].grupo; tNave=&pvLinea->grupos[vAGrupo]; n=0; if (tNave->escudo == escudo) if (tNave->blindaje ==blinda) if (!tNave->rondaMuerta) if (tNave->capturada==capturada) n=1; if (n==0) ASSERT(0); } } else { for (vAGrupo=0,tNave=&pvLinea->grupos[0];vAGrupo<pvLinea->nGrupos;vAGrupo++,tNave++) { if (!tNave->nGrupo) { if (iH==-1) iH=vAGrupo; } else { if (tNave->escudo == escudo) if (tNave->blindaje ==blinda) if (!tNave->rondaMuerta) if (tNave->capturada==capturada) break; } } if (vAGrupo>=pvLinea->nGrupos) vAGrupo=-1; } if (vAGrupo!=-1) { // traspasar pvLinea->grupos[vAGrupo].nGrupo++; vNave->nGrupo--; if (pvLinea->nav2grupos) pvLinea->nav2grupos[-iVict-1]=vAGrupo; } else { // Nuevo grupo if (iH==-1) { // no hay sitio, ampliar iH=pvLinea->nGrupos; pvLinea->nGrupos++; if (iH>=pvLinea->maxGrupos) { pvLinea->maxGrupos+=1000; pvLinea->grupos=(TNave *)realloc(pvLinea->grupos,(pvLinea->maxGrupos)*sizeof(TNave)); if (!pvLinea->grupos) { log("Sin memoria"); return 0; } memset(&pvLinea->grupos[iH],0,1000*sizeof(TNave)); vNave=NULL; // en principio no me hace falta. Ojo movido if (pig=pvLinea->indiceGrupos) { pig=(TIndiceGrupos *)realloc(pig,(pvLinea->maxGrupos)*sizeof(TIndiceGrupos)); if (!pig) free(pvLinea->indiceGrupos); pvLinea->indiceGrupos=pig; } } } memcpy(&pvLinea->grupos[iH],&pvLinea->grupos[iGrV],sizeof(TNave)); pvLinea->grupos[iGrV].nGrupo--; pvLinea->grupos[iH].nGrupo=1; pvLinea->grupos[iH].blindaje=blinda; pvLinea->grupos[iH].escudo=escudo; pvLinea->grupos[iH].capturada=capturada; if (pvLinea->nav2grupos) pvLinea->nav2grupos[-iVict-1]=iH; if (pig=pvLinea->indiceGrupos) { n=buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,capturada,escudo,blinda,1); if (n>0) { if ((pig[n-1].blindaje>blinda && pig[n-1].capturada==capturada) || pig[n-1].blindaje<-1) ASSERT(0); } if (n<pvLinea->nIndiceGrupos-1) { if ((pig[n+1].blindaje<blinda && pig[n+1].capturada==capturada) || pig[n+1].blindaje<-1) ASSERT(0); } if (n<pvLinea->nIndiceGrupos) memmove(pig+n+1,pig+n,sizeof(TIndiceGrupos)*(pvLinea->nIndiceGrupos-n)); pig[n].blindaje=blinda; pig[n].escudo=escudo; pig[n].capturada=capturada; pig[n].grupo=iH; pvLinea->nIndiceGrupos++; DEBUG_ONLY(checkIndex(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,pvLinea->grupos)); ASSERT(n==buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,capturada,escudo,blinda,0,iH)); } } } } } return 1; } int CMotor4::batDispara(int ronda) { int fuego,fuego2; int navesMuertas[2]; int nGrupo; int navesAhorro=0; int iH,iVict,bando,fr,n,*pi; int iFl,iLin,iGr; TFlotas *pFlota; TLinea *pLinea; TNave *iNave; int iFlV,iLiV,iGrV; TFlotas *pvFlota; TLinea *pvLinea; TNave * vNave; TIndiceGrupos *pig; unsigned __int8 capturada; bool bMuerta; TRondas *pRonda=&m_rondas[ronda]; DWORD inicio,fin; pRonda->n=ronda; pRonda->disparos[0]=pRonda->disparos[1]=0; pRonda->fuerza[0]=pRonda->fuerza[1]=0; pRonda->absor[0]=pRonda->absor[1]=0; navesMuertas[0]=navesMuertas[1]=0; for (bando=0;bando<2;bando++) { TRACE("Ronda %d bando %d",ronda,bando); inicio=GetTickCount(); for (iFl=0;iFl<m_nFlotas[1-bando];iFl++) { pFlota=&m_flotas[1-bando][iFl]; for (iLin=0;iLin<pFlota->nLineas;iLin++) { pLinea=&pFlota->lineas[iLin]; pLinea->nav2grupos=NULL; if (pLinea->nGrupo>=10000000) TRACE(" Uf(%d)",pLinea->nGrupo); if (pLinea->maxGrupos==-1) { // Array lineal de naves pLinea->indiceGrupos=NULL; n=sizeof(int)*pLinea->nGrupo; pi=pLinea->nav2grupos=(int *)malloc(n); if (pi) { for (iGrV=0;iGrV<pLinea->nGrupos;iGrV++) { if (!pLinea->grupos[iGrV].rondaMuerta) *(pi++)=iGrV; } } } else { // Naves agrupadas if (pLinea->nGrupo<25000000 && pLinea->nGrupo>0) { // Array directo n=sizeof(int)*pLinea->nGrupo; pi=pLinea->nav2grupos=(int *)malloc(n); if (pi) { for (iGrV=0;iGrV<pLinea->nGrupos;iGrV++) { if (!pLinea->grupos[iGrV].rondaMuerta) for (n=pLinea->grupos[iGrV].nGrupo;n;n--) *(pi++)=iGrV; } } n=sizeof(TIndiceGrupos)*pLinea->maxGrupos; pig=pLinea->indiceGrupos=(TIndiceGrupos *)malloc(n); pLinea->nIndiceGrupos=0; if (pig) { for (iGrV=0;iGrV<pLinea->nGrupos;iGrV++) { if (!pLinea->grupos[iGrV].rondaMuerta) { pig[iGrV].blindaje=pLinea->grupos[iGrV].blindaje; pig[iGrV].escudo=pLinea->grupos[iGrV].escudo; pig[iGrV].capturada=pLinea->grupos[iGrV].capturada; } else { pig[iGrV].blindaje=0; pig[iGrV].escudo=0; pig[iGrV].capturada=-1; // que no se mezcle con otros grupos pig[iGrV].grupo=iGrV; } pig[iGrV].grupo=iGrV; pLinea->nIndiceGrupos++; } qsort(pig,pLinea->nIndiceGrupos,sizeof(TIndiceGrupos),ordenIndice); } } } } } for (iFl=0;iFl<m_nFlotas[bando];iFl++) { pFlota=&m_flotas[bando][iFl]; for (iLin=0;iLin<pFlota->nLineas;iLin++) { pLinea=&pFlota->lineas[iLin]; for (iGr=0;iGr<pLinea->nGrupos;iGr++) { iNave=&pLinea->grupos[iGr]; if (!iNave->rondaMuerta) { if (navesMuertas[1-bando]>=m_navBandos[1-bando]) continue; // No hay naves enemigas vivas, paso nGrupo=iNave->nGrupo; if (!nGrupo) nGrupo=1; ASSERT(nGrupo>=0); for (;nGrupo;nGrupo--) { fuego=fuego2=m_flotas[bando][iFl].lineas[iLin].ataques; if (!fuego) break; for (fr=0;;fr++) { fuego=fuego2=m_flotas[bando][iFl].lineas[iLin].ataques; iVict=rand(); if (m_navBandos[1-bando]>RAND_MAX) iVict=iVict*(1+RAND_MAX)+rand(); iVict%=m_navBandos[1-bando]; iH=iVict; iVict=iH; for (iFlV=0;iFlV<m_nFlotas[1-bando];iFlV++) { pvFlota=&m_flotas[1-bando][iFlV]; for (iLiV=0;iLiV<pvFlota->nLineas;iLiV++) { pvLinea=&pvFlota->lineas[iLiV]; if (pvLinea->nGrupo>iVict) { if (pvLinea->maxGrupos==-1) { //Array lineal iGrV=pvLinea->nav2grupos[iVict]; iVict=-1; } else { if (pvLinea->nav2grupos) { iGrV=pvLinea->nav2grupos[iVict]; iVict=-iVict-1; } else { n=0; for (iGrV=0;iGrV<pvLinea->nGrupos;iGrV++) { if (!pvLinea->grupos[iGrV].rondaMuerta) { iVict-=pvLinea->grupos[iGrV].nGrupo; n+=pvLinea->grupos[iGrV].nGrupo; if (n>pvLinea->nGrupo) ASSERT(0); if (iVict<0) break; } else iVict=iVict; } } } if (iVict>=0) ASSERT(0); if (iVict<0) break; } else { iVict-=pvLinea->nGrupo; } } if (iVict<0) break; } if (pvLinea->maxGrupos==-1) vNave=&pvLinea->grupos[iGrV]; else vNave=&m_flotas[1-bando][iFlV].lineas[iLiV].grupos[iGrV]; // mina térmica if (pLinea->gid==223) { // victima coste igual o inferior a crucero if (m_costes[pvLinea->gid-200].costeM+m_costes[pvLinea->gid-200].costeC+m_costes[pvLinea->gid-200].costeD<=29000) { fuego=fuego2=2*(vNave->escudo+vNave->blindaje); almacenar(pLinea,iNave,iGr,-iGr-1,0,-1,0); navesMuertas[bando]++; } else { fuego=fuego2=0; } } pRonda->disparos[bando]++; pRonda->fuerza[bando]+=fuego; int escudo,blinda,maxBlinda,maxEscudo; capturada=vNave->capturada; maxEscudo=pvLinea->maxEscudo; maxBlinda=pvLinea->maxBlindaje; escudo=vNave->escudo; blinda=vNave->blindaje; if (escudo>0) { if (fuego<escudo) { pRonda->absor[bando]+=fuego; } else { pRonda->absor[bando]+=escudo; } } if (fuego<escudo) { int perc=(int)((100.0*fuego)/maxEscudo); fuego=maxEscudo*perc; fuego/=100; fuego2=fuego; } if (escudo<=0 || fuego>0) { fuego-=escudo; escudo-=fuego2; if (fuego<0) fuego=0; } else fuego=0; if (escudo<0) escudo=0; bMuerta=false; if (fuego>0) { if (blinda>=0) { if ((blinda-=fuego)<0) blinda=-1; else { if (blinda<0.7*maxBlinda) { if ((rand()%100) >(100*blinda)/maxBlinda) blinda=-1; } } if (blinda==-1) { // Nave murio con este disparo if (pLinea->gid==222 && pvLinea->gid<400 && pvLinea->gid!=212 && pvLinea->gid!=223) { // y no es defensa ni sat ni mina capturada=1; pFlota->capturas[pvLinea->gid]++; } navesMuertas[1-bando]++; bMuerta=true; } } } if (!almacenar(pvLinea,vNave,iGrV,iVict,escudo,blinda,capturada)) return 0; if (bMuerta) { if (navesMuertas[1-bando]>=m_navBandos[1-bando]) { // Cortar iteraciones, ya no quedan enemigas nGrupo=1; // Salir del bucle de naves atacantes agrupadas break; // Salir de fuegos rápidos } } if (!fuegoRapido(pLinea->gid,pvLinea->gid)) break; } } } } } } for (iFl=0;iFl<m_nFlotas[1-bando];iFl++) { pFlota=&m_flotas[1-bando][iFl]; for (iLin=0;iLin<pFlota->nLineas;iLin++) { pLinea=&pFlota->lineas[iLin]; if (pLinea->nav2grupos) free(pLinea->nav2grupos); pLinea->nav2grupos=NULL; if (pLinea->indiceGrupos) free(pLinea->indiceGrupos); pLinea->indiceGrupos=NULL; } } fin=GetTickCount(); TRACE(" %f secs\n",(fin-inicio)/1000.0); } return 1; }
Ah, sí, los fuegos rápidos. Se cargan una sola vez al inicio del programa, y son un array tal que m_pFuegoRapido[atacante-200][defensor-200]=fuegoRápido. El -200 es porque las naves están numeradas a partir del 200, y no es plan de gastar memoria para guardar fuegos rápidos de edificios.
Y por cierto, la parte de guardar en memoria la representación de las naves y su agrupación por daño sufrido durante la batalla... es un dolor. Me puse ciego a porros para hacerlo, así que si no lo entendéis ya sabéis el método xD Como pista, hay dos o tres formas de guardar la batalla en memoria según lo grande que sea, pues las formas más eficientes en velocidad gastan más memoria, y viceversa. Así que el programa estima y decide por una de ellas. Y la de batallas realmente grandes, es realmente complicada xD
Bueno, creo que está completo el código, así que debería funcionar sin problemas.
Hale, ya tenéis comida. Ahora respondo personales
La de veces que me lo has tenido que decir para que me enterara de lo que me pedías xDno has dado ninguna descripción de las estructuras de datos que usa el motor de batallas
Desarrollado por phpBB® Forum Software © phpBB Limited
Traducción al español por phpBB España