Tampoco sobre el modo conque chequea si hubo victoria.
Lo que pregunto tiene que ver conque quiero agregarle cosas, por ejemplo:
- Opción de que jueguen más de 2 jugadores.
- Si es posible, opción de casilleros con otras formas, de modo que la cantidad de direcciones posibles sea distinta a 8. Por ahora sólo vi de 6:
https://es.wikipedia.org/wiki/Teselado_hexagonal
- Opción de que no se gane por hacer una línea de signos requeridos, sino por ser quien haya hecho más cuando el tablero esté lleno.
- Opción de que se gane por tener la mayor cantidad de unidos, independientemente de cuan larga sea la línea. Aunque debo pensar si esto tendría gracia.
- Opción de que se gane por haber formado la línea más larga posible (puede ocurrir antes de que el casillero se llene).
- Opciones anti, como el antichess, o sea, que en vez de ganar por hacer una cosa u otra, eso lleve a perder.
- Opción de que se gane no por hacer una línea, sino alguna figura. Por ejemplo una L.
- Opción de que gane quien haga la figura más grande.
- Opción de que en vez de ser signos se pongan letras y gane quien 1ero forme una palabra.
- Que gane quien forme más palabras.
- Las letras a poner van rotando, el jugador no elige. Por ejemplo si hay que formar "Win".
- Al comienzo los jugadores se turnan en elegir una letra, luego empieza el juego poniéndolas según el orden conque las eligieron.
- Lo mismo pero en cualquier orden.
- Lo mismo pero puedes usar las letras de tu oponente.
- Repetición de letras se permite.
Y tal vez más... Algunas cosas no son excluyentes.
Algunas cosas quizá sea mejor hacerlas en un programa aparte, pero ya que son juegos tan similares sería bueno un "todo en 1" ¿no? Además no sé cuales debería hacer aparte, tal vez el que se puede poner letras y el que es sobre formar figuras. Serían 3. ¿Ustedes harían 3 juegos o más o menos?
Teniendo en cuenta todo eso, quisiera que mi código esté mejor preparado, porque intenté hacrlo eficiente pero en eso decidí hacerlo así nomás y por ahora está así. ¿Cómo lo mejorarían?
Imagen para referencia:

Frame 1:
Código
CasillerosPorFila = 9; JuntosRequeridos = 3; MarcadorDeX = "Humano"; MarcadorDe0 = "IA"; Jugadores = "HumanoIA"; // Usado en el botón de quién marca con X: function CambiarMarcadorDeX () { if (MarcadorDeX == "Humano") { MarcadorDeX = "IA"; } else { MarcadorDeX = "Humano"; } Jugadores = MarcadorDeX+MarcadorDe0; HacerTablero(); } // Usado en el botón de quién marca con 0: function CambiarMarcadorDe0 () { if (MarcadorDe0 == "IA") { MarcadorDe0 = "Humano"; } else { MarcadorDe0 = "IA"; } Jugadores = MarcadorDeX+MarcadorDe0; HacerTablero(); } // Usado ahora y en general cuando se cambia la configuración de la partida: function HacerTablero () { // Esto se irá especificando en el próximo while: Situacion = []; PosiblesAcciones = []; // Los casilleros se cuentan desde 0: MaxCasillero = CasillerosPorFila*CasillerosPorFila-1; // Las columnas también. Esto es para no repetir restas por ahí: MaxColumna = CasillerosPorFila-1; LargoDeCasilleros = 384/CasillerosPorFila; NroDeCasilleroaColocar = -1; // Sus columnas y filas se cuentan desde 0, // sirven para posicionarlos más fácil: Columna = 0; Fila = 0; do { NroDeCasilleroaColocar++; // v es vacío: Situacion.push("v"); PosiblesAcciones.push(NroDeCasilleroaColocar); CasilleroaColocar = "Casillero"+NroDeCasilleroaColocar; // set ("SignoEn"+CasilleroaColocar, "v"); // sCasillero tiene código: attachMovie("sCasillero", CasilleroaColocar, NroDeCasilleroaColocar); setProperty (CasilleroaColocar, _x, LargoDeCasilleros*Columna); setProperty (CasilleroaColocar, _y, LargoDeCasilleros*Fila); setProperty (CasilleroaColocar, _width, LargoDeCasilleros); setProperty (CasilleroaColocar, _height, LargoDeCasilleros); Columna++; if (Columna == CasillerosPorFila) { Columna = 0; Fila++; } // Para que al presionar el botón se sepa qué modificar: set (CasilleroaColocar+".CasilleroAsociado", NroDeCasilleroaColocar); // trace("Colocado el "+NroDeCasilleroaColocar); } while (NroDeCasilleroaColocar < MaxCasillero); // Para que no muestre el mensaje de victoria: Win = "No"; // Esto es para evitar restas: LastNroDeAcccionPosible = PosiblesAcciones.length-1; trace ("LastNroDeAcccionPosible: "+LastNroDeAcccionPosible); SignoDeTurno = "X"; if (Jugadores == "HumanoIA") { gotoAndStop(2); } else if (Jugadores == "IAHumano") { TurnoDeIA(); if (Win == "No") { // OJO QUE SI HAY EMPATE NO DEBE IR AL F2, O NO ES NEC gotoAndStop(2); } } else if (Jugadores == "HumanoHumano") { gotoAndStop(2); } else { // IA VS IA: InutilizarBotones(); gotoAndStop(3); } } HacerTablero(); // Usada cuando el humano marca en un casillero: function HumanoHaMarcado () { // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); // trace("Humano ha marcado"); // Inutilizar botón del casillero marcado: setProperty (eval("Casillero"+CasilleroMarcado+".Boton"), _visible, false); // Agregar signo: // SignosColocados++; eval("Casillero"+CasilleroMarcado).attachMovie("s"+SignoDeTurno, "Signo", 1); Situacion[CasilleroMarcado] = SignoDeTurno; // set ("SignoEnCasillero"+CasilleroMarcado, "X"); // ¿Gana? // Si esta función dice que no, usa otras: ChequearVertical(); if (Win == "Sí") { // Sí, inutilizar botones del tablero // (debería ser sólo los activos): InutilizarBotones(); // Mostrar mensaje de victoria: attachMovie("sGano"+SignoDeTurno, "Mensaje", NroDeCasilleroaColocar+1); UbicarMensaje(); } else if (PosiblesAcciones.length>=2) { // Sino, si aún hay >=2 acciones posibles // (la que usó aún no se quitó): // Quitar su acción de las posibles acciones: // Se busca en qué posición del array está: AccionRevisandose = -1; // Condición original: AccionRevisandose < LastNroDeAcccionPosible do { AccionRevisandose++; if (PosiblesAcciones[AccionRevisandose] == CasilleroMarcado) { // Se elimina la acción de la lista de posibles: PosiblesAcciones.splice(AccionRevisandose, 1); trace (PosiblesAcciones.join("")); break; } } while (true); LastNroDeAcccionPosible--; trace ("LastNroDeAcccionPosible disminuyó: "+LastNroDeAcccionPosible); // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); CambiarSigno(); if (Jugadores == "HumanoIA" or Jugadores == "IAHumano") { TurnoDeIA(); } } else { // (sólo queda 1 acción en la lista, // pero es la que acaba de usar, // que debe borrarse, así que no quedan) trace ("Empate luego de que marcó el humano"); // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); Empate(); } } // Usada en ChequeoHorizontal y requerida en otros chequeos: function ObtenerColumnayFilaDelMarcado () { ColumnaDelMarcado = CasilleroMarcado%CasillerosPorFila; // trace ("Su Columna según el cálculo es: "+ColumnaDelMarcado); FilaDelMarcado = Math.floor(CasilleroMarcado/CasillerosPorFila); // trace ("Su Fila: "+FilaDelMarcado); } // Usada cuando alguien gana o en HacerTablero si es IA VS IA: function InutilizarBotones () { BotonesInutilizados = -1; do { BotonesInutilizados++; setProperty ("Casillero"+BotonesInutilizados+".Boton", _visible, false); } while (BotonesInutilizados<MaxCasillero); } // Usada cuando hay que ubicar un mensaje, duh: function UbicarMensaje () { setProperty (Mensaje, _x, 192.4); setProperty (Mensaje, _y, 192); // gotoAndStop (3); } // En caso de empate: function Empate () { attachMovie("sEmpate", "Mensaje", NroDeCasilleroaColocar+1); UbicarMensaje(); // Para que en el modo IA VS IA, la IA no juegue más: Win = "Sí"; trace("Empate"); } function CambiarSigno () { if (SignoDeTurno == "X") { SignoDeTurno = 0; } else { SignoDeTurno = "X"; } } function TurnoDeIA () { // Elegir una acción al azar: NroDeAccionElegida = random(PosiblesAcciones.length); AccionElegida = PosiblesAcciones[NroDeAccionElegida]; trace ("IA ha marcado: "+AccionElegida); // Eliminar la que está en el nro elegido: PosiblesAcciones.splice(NroDeAccionElegida, 1); trace (PosiblesAcciones.join("")); LastNroDeAcccionPosible--; trace ("LastNroDeAcccionPosible disminuyó: "+LastNroDeAcccionPosible); eval("Casillero"+AccionElegida).attachMovie("s"+SignoDeTurno, "Signo", 0); Situacion[AccionElegida] = SignoDeTurno; // Inutilizar el botón de ahí: setProperty (eval("Casillero"+AccionElegida+".Boton"), _visible, false); // Ver si IA ganó: CasilleroMarcado = AccionElegida; // trace ("JuntosRequeridos: "+JuntosRequeridos); ChequearVertical(); // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); if (Win == "Sí") { // Sí, inutilizar botones del tablero // (debería ser sólo los activos): InutilizarBotones(); // Mostrar mensaje de victoria: attachMovie("sGano"+SignoDeTurno, "Mensaje", NroDeCasilleroaColocar+1); UbicarMensaje (); } else if (PosiblesAcciones.length == 0) { trace ("Empate luego de que marcó la IA"); // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); Empate(); } else { CambiarSigno(); } }
ChequeoHorizontal lo que hace es fijarse si hay victoria. Si hay, hace que Win sea "Sí". Sino, llama a otros chequeos que hacen cosas parecidas. Pueden ver el código en mi otro tema reciente, pero como dije no es la cuestión aquí.
Frame 2:
stop();
Nada relevante aquí, simplemente ocurre el juego, el jugador hace clic en los casilleros. Los casilleros tienen un botón con esto:
Código:
on (release) {
_level0.CasilleroMarcado = _parent.CasilleroAsociado;
_level0.HumanoHaMarcado();
}
Frame 3:
Aquí funciona el modo IA VS IA, un objeto tiene:
Código
onClipEvent (enterFrame) { trace("SignoDeTurno: "+_level0.SignoDeTurno); _level0.TurnoDeIA(); trace("Win: "+_level0.Win); if (_level0.Win == "No") { trace("SignoDeTurno: "+_level0.SignoDeTurno); _level0.TurnoDeIA(); trace("Win: "+_level0.Win); } trace("Win: "+_level0.Win); // No va un else, esto es que si la IA ganó en su 1er turno o... // en su 2ndo, frana: if (_level0.Win == "Sí") { trace("Va al frame 2"); _root.gotoAndStop (2); } }
No me gusta mucho usar distintos frames pero parece la forma más eficiente de evitar ifs, evals, etc, no sé...