// Signos en línea en tableros cuadrados:
// Este programa tiene básicamente ?????????????????????????????????????? etapas,
// que se pueden resumir así:
// Nota: La situación inicial, en que hay 0 signos colocados,
// estará guardada en la lista nro 0.
// 1:
// Probar acciones en cada situación de la lista,
// guardando en una nueva lista las nuevas situaciones (que no...
// sean victoria ni empate). Repetir con cada lista hasta la que...
// tenga situaciones en que sólo 1 acción es posible (por...
// ejemplo en el 3 en línea es 8).
// 2: ACTUALIZAR ESTA
// En las situaciones no resueltas, probar las acciones.
// Si las consecuencias tienen RE, anotar cuantas de ellas...
// son victoria de X, 0 o empate y anotar la acción que...
// cause la RE más favorable, considerando secundariamente...
// las cantidades.
JuntosRequeridos = 3;
CasillerosPorFila = 3;
// Contando desde 0:
MaxColumna = CasillerosPorFila-1;
Casilleros = CasillerosPorFila*CasillerosPorFila;
// Están numerados así:
// 0 1 2
// 3 4 5
// 6 7 8
MaxCasillero = Casilleros-1;
// En las listas L_SaE se irán poniendo las situaciones a...
// experimentar que tengan _ signos colocados.
// En la lista 0 agregar una situación, aún no se dice cual:
L0SaE1 = [];
// A continuación se especifica cómo es, agregando v
// (que significa vacío) en lo que serían los casilleros,
// los elementos del array:
ValoraAgregar = -1;
do {
ValoraAgregar++;
L0SaE1.push("v");
} while (ValoraAgregar < MaxCasillero);
delete ValoraAgregar;
// Los datos de las situaciones no están en las listas,
// se crean aparte. Con esta variable se evita repetidamente...
// convertir en texto y concatenar:
S_ = "S"+(L0SaE1.join(""));
// Datos de la situación:
// Usada para fácilmente saber de qué signo es turno:
set (S_+"Turno", "X");
// En otros casos usada para evitar probar acciones...
// innecesarias y con LastAPosible para saber si sólo queda 1:
set (S_+"FirstAPosible", 0);
set (S_+"LastAPosible", MaxCasillero);
NroDeListaRevisandose = -1;
// Última lista que se revisará en la etapa 1:
// LastListaDeEt1 = MaxCasillero;
// /////////////////////////////////////////////
// ///////////////// Etapa 1 /////////////////
// /////////////////////////////////////////////
// Usada a continuación y durante la etapa 1 (Et1)...
// cuando no hay más situaciones en la lista revisándose:
function BuscarOtraListaEt1 () {
trace("Ejecutando BuscarOtraListaEt1");
NroDeListaRevisandose++;
// Si las situaciones de la lista tienen más de 1 opción:
if (NroDeListaRevisandose < MaxCasillero) {
// Para evitar concatenar repetidamente:
L_SaE = "L"+NroDeListaRevisandose+"SaE";
NextL_SaE = "L"+(NroDeListaRevisandose+1)+"SaE";
NroDeSExperimentandose = 1;
// También para evitar concatenar repetidamente:
// L_SaE_ = L_SaE+NroDeSExperimentandose;
L_SaE_ = L_SaE+"1";
// Usado en EvaluarConocimientoSobreSEt1 para...
// nombrar las situaciones nuevas que se logren:
SituacionesNuevas = 0;
trace("Comienzan experimentos en una nueva lista, la "+NroDeListaRevisandose);
PrepararSaE();
} else {
trace( "La próxima lista tiene situaciones de sólo 1 opción; inicia la etapa 2.");
// IniciarEtapa2();
gotoAndStop(4);
}
}
BuscarOtraListaEt1();
// Usada cuando se elege una SaE, en BuscarOtraListaEt1 y...
// BuscarOtraSituacionEt1:
function PrepararSaE () {
trace("Ejecutando PrepararSaE");
trace("Se inician experimentos en otra situación de la lista, la nro "+NroDeSExperimentandose);
SituacionBase = eval(L_SaE_);
S_ = "S"+(SituacionBase.join(""));
Turno = eval(S_+"Turno");
FirstActionPosible = eval(S_+"FirstAPosible");
LastActionPosible = eval(S_+"LastAPosible");
Action = FirstActionPosible;
}
// Usada en frame 2 (o etapa 1) repetidamente:
function BuscarSituacionesDistantes () {
// Plantear situación porque puede modificarse pero...
// podría requerirse su estado original luego:
Situacion = SituacionBase.slice();
trace("La situación experimentándose es "+Situacion);
EvaluarAplicabilidadEt1();
}
// Usada luego de que cambia la SaE y/o la acción:
function EvaluarAplicabilidadEt1 () {
trace("Ejecutando EvaluarAplicabilidadEt1");
if (Situacion[Action] == "v") {
trace("La acción "+Action+" es realizable.");
AplicarAccionEt1();
} else {
trace("La acción "+Action+" no es realizable.");
BuscarOtraAccionEt1();
}
}
// Usada luego de EvaluarAplicabilidadEt1,
// si una acción es realizable:
function AplicarAccionEt1 () {
trace("Ejecutando AplicarAccionEt1");
Situacion[Action] = Turno;
trace("Se realizó la acción "+Action+"; ahora la situación es "+Situacion);
// ¿Ganó?
// Si no se detecta victoria vertical,
// revisa de otros modos (ver las funciones Chequear):
ChequearVertical();
if (Win == "No") {
EvaluarConocimientoSobreSEt1();
}
// ¿Queda alguna acción sin probar en la situación?
BuscarOtraAccionEt1();
}
// Usada en EvaluarAplicabilidadEt1 cuando una acción no es...
// realizable, y luego de AplicarAccionEt1:
function BuscarOtraAccionEt1 () {
trace("Ejecutando BuscarOtraAccionEt1");
if (Action < LastActionPosible) {
// Si queda alguna acción sin probar...
// en la situación, probarla:
Action++;
// Se ejecutará BuscarSituacionesDistantes.
} else {
trace("No hay más acciones realizables.");
BuscarOtraSituacionEt1();
}
}
// Usada en AplicarAccionEt1 cuando no hay victoria (ni empate,
// aunque por ahora no ocurren):
function EvaluarConocimientoSobreSEt1 () {
trace("Ejecutando EvaluarConocimientoSobreSEt1");
SituacionJoined = Situacion.join("");
NewS_ = "S"+SituacionJoined;
NewS_BestAction = NewS_+"BestAction";
// ¿Se ha llegado antes a la situación?
if (eval(NewS_BestAction) == undefined) {
// No, anotar que debe investigarse:
SituacionesNuevas++;
// Copiar array (porque no se puede normalmente):
set (NextL_SaE+SituacionesNuevas, Situacion.slice());
trace("Esa situación no está anotada; se anota como nro "+SituacionesNuevas);
set(NewS_BestAction, "Desconocida");
if (Turno == "X") {
set (NewS_+"Turno", "0");
} else {
set (NewS_+"Turno", "X");
}
// Averiguar cual es su 1er acción posible:
AccionRevisandose = -1;
do {
AccionRevisandose++;
if (Situacion[AccionRevisandose] == "v") {
set (NewS_+"FirstAPosible", AccionRevisandose);
break;
}
} while (true);
// Averiguar cual es su última acción posible:
AccionRevisandose = Casilleros;
do {
AccionRevisandose--;
if (Situacion[AccionRevisandose] == "v") {
set (NewS_+"LastAPosible", AccionRevisandose);
break;
}
} while (true);
}
}
// Usada en BuscarOtraAccionEt1 cuando no hay más acciones posibles:
function BuscarOtraSituacionEt1 () {
trace("Ejecutando BuscarOtraSituacionEt1");
NroDeSExperimentandose++;
if (eval(L_SaE+NroDeSExperimentandose) != undefined) {
// Hay otra situación en la lista,
// prepararse a usarla:
L_SaE_ = L_SaE+NroDeSExperimentandose;
PrepararSaE();
} else {
trace( "No hay más situaciones a experimentar en la lista actual, se mirará otra.");
BuscarOtraListaEt1();
}
}
// /////////////////////////////////////////////
// ///////////////// Chequeos ////////////////
// /////////////////////////////////////////////
// Usada en ChequeoHorizontal y requerida en otros casos:
function ObtenerColumnayFilaDelMarcado () {
FilaDelMarcado = Math.floor(Action/CasillerosPorFila);
ColumnaDelMarcado = Action%CasillerosPorFila;
}
function ChequearVertical () {
// trace ("Ejecutando ChequearVertical");
//
// SOLO FUNCIONA SI CasillerosPorFila >= JuntosRequeridos.
//
// Se revisará la vertical. Desde el casillero más arriba...
// que pueda estar incluído en la línea,
// hasta el casillero marcado. Si se haya alguno que no...
// tenga la marca requerida, se repite el proceso mirando...
// desde uno más abajo del fallado, y mirando ahora hasta...
// más abajo, según corresponda:
Desde = Action-CasillerosPorFila*(JuntosRequeridos-1);
// Mientras el casillero no exista:
while (Desde<0) {
// trace ("Desde es "+Desde+", se aumentará");
// Indicar que se empiece a mirar desde más abajo:
Desde = Desde+CasillerosPorFila;
}
do {
Hasta = Desde+CasillerosPorFila*(JuntosRequeridos-1);
if (Hasta>MaxCasillero) {
// Para ganar se necesitaría más casilleros hacia...
// abajo de los que hay, terminar análisis:
// trace ("No hay suficientes cuadraditos abajo");
break;
}
Puntero = Desde;
// trace ("Comenzando chequeo desde "+Desde+" hasta "+Hasta);
// Puede cambiar:
Win = "Sí";
do {
// trace ("Chequando el casillero "+Puntero);
if (Situacion[Action] != Situacion[Puntero]) {
Win = "No";
Desde = Puntero+CasillerosPorFila;
break;
}
Puntero = Puntero+CasillerosPorFila;
} while (Puntero<=Hasta);
} while (Desde<=Action && Win == "No");
if (Win == "No") {
ChequearHorizontal();
}
}
function ChequearHorizontal () {
// trace ("Ejecutando ChequearHorizontal");
// Es similar al chequeo vertical, pero aquí no sirve...
// sumar o restar a un puntero que marque el casillero...
// porque puede existir ese casillero pero no estar en...
// un costado. En vez de eso, se obtiene su columna y...
// fila, se modifica la columna si es posible,
// y se calcula cual es el casillero a mirar:
ObtenerColumnayFilaDelMarcado();
DesdeColumna = ColumnaDelMarcado-JuntosRequeridos+1;
// Para que no mire cuadraditos inexistentes en la izq:
if (DesdeColumna<0) {
DesdeColumna = 0;
}
do {
HastaColumna = DesdeColumna+JuntosRequeridos-1;
if (HastaColumna>MaxColumna) {
// Para ganar se necesitaría más casilleros hacia...
// la derecha de los que hay, terminar análisis:
// trace ("No hay suficientes cuadraditos a la derecha");
break;
}
Puntero = DesdeColumna;
// trace ("Comenzando chequeo desde "+DesdeColumna+" hasta "+HastaColumna);
// Puede cambiar:
Win = "Sí";
do {
CasilleroaMirar = FilaDelMarcado*CasillerosPorFila+Puntero;
// trace ("Chequando el casillero "+CasilleroaMirar);
if (Situacion[Action] != Situacion[CasilleroaMirar]) {
Win = "No";
DesdeColumna = Puntero+1;
break;
}
Puntero++;
} while (Puntero<=HastaColumna);
} while (DesdeColumna<=ColumnaDelMarcado && Win == "No");
if (Win == "No") {
ChequearDesdeUpIzq();
}
}
// La diagonal así \
function ChequearDesdeUpIzq () {
// trace ("Ejecutando ChequearDesdeUpIzq");
DesdeColumna = ColumnaDelMarcado-JuntosRequeridos+1;
// trace("DesdeColumna: "+DesdeColumna);
DesdeFila = FilaDelMarcado-JuntosRequeridos+1;
// trace("DesdeFila: "+DesdeFila);
// Para que no mire cuadraditos inexistentes:
if (DesdeColumna<DesdeFila) {
Sumar = DesdeColumna;
} else {
Sumar = DesdeFila;
}
// trace("Sumar: "+Sumar);
if (Sumar<0) {
// trace("Sumando.");
DesdeColumna = DesdeColumna-Sumar;
// trace("DesdeColumna: "+DesdeColumna);
DesdeFila = DesdeFila-Sumar;
// trace("DesdeFila: "+DesdeFila);
}
do {
HastaColumna = DesdeColumna+JuntosRequeridos-1;
if (HastaColumna>MaxColumna) {
// Para ganar se necesitaría más casilleros hacia...
// la derecha de los que hay, terminar análisis:
// trace ("No hay suficientes cuadraditos a la derecha");
break;
}
HastaFila = DesdeFila+JuntosRequeridos-1;
// Sirve usar MaxColumna en vez de crear MaxFila...
// porque como el tablero es cuadrado serían iguales:
if (HastaFila>MaxColumna) {
// Para ganar se necesitaría más casilleros hacia...
// abajo de los que hay, terminar análisis:
// trace ("No hay suficientes cuadraditos abajo");
break;
}
PunteroDeColumna = DesdeColumna;
PunteroDeFila = DesdeFila;
// trace ("Comenzando chequeo desde columna "+DesdeColumna+" y fila "+DesdeFila);
// trace ("hasta columna "+HastaColumna+" y fila "+HastaFila);
// Puede cambiar:
Win = "Sí";
do {
CasilleroaMirar = PunteroDeFila*CasillerosPorFila+PunteroDeColumna;
// trace ("Chequando el casillero "+CasilleroaMirar);
if (Situacion[Action] != Situacion[CasilleroaMirar]) {
Win = "No";
DesdeColumna = PunteroDeColumna+1;
DesdeFila = PunteroDeFila+1;
break;
}
PunteroDeColumna++;
PunteroDeFila++;
} while (PunteroDeColumna<=HastaColumna);
} while (DesdeColumna<=ColumnaDelMarcado && Win == "No");
if (Win == "No") {
ChequearDesdeDownIzq();
}
}
// La diagonal así /
function ChequearDesdeDownIzq () {
// trace ("Ejecutando ChequearDesdeDownIzq");
DesdeColumna = ColumnaDelMarcado-JuntosRequeridos+1;
// trace("DesdeColumna: "+DesdeColumna);
DesdeFila = FilaDelMarcado+JuntosRequeridos-1;
// trace("DesdeFila: "+DesdeFila);
// Para que no mire cuadraditos inexistentes:
ColumnasInexistentes = 0;
if (DesdeColumna<0) {
ColumnasInexistentes = DesdeColumna*-1;
}
FilasInexistentes = 0;
// Está bien usar MaxColumna porque MaxFila sería igual:
if (DesdeFila>MaxColumna) {
FilasInexistentes = DesdeFila-MaxColumna;
}
if (ColumnasInexistentes>=FilasInexistentes) {
Ajuste = ColumnasInexistentes;
} else {
Ajuste = FilasInexistentes;
}
// trace("Ajuste: "+Ajuste);
if (Ajuste>0) {
// trace("Ajustando.");
DesdeColumna = DesdeColumna+Ajuste;
// trace("DesdeColumna: "+DesdeColumna);
DesdeFila = DesdeFila-Ajuste;
// trace("DesdeFila: "+DesdeFila);
}
do {
HastaColumna = DesdeColumna+JuntosRequeridos-1;
if (HastaColumna>MaxColumna) {
// Para ganar se necesitaría más casilleros hacia...
// la derecha de los que hay, terminar análisis:
// trace ("No hay suficientes cuadraditos a la derecha");
break;
}
HastaFila = DesdeFila-JuntosRequeridos+1;
if (HastaFila<0) {
// Para ganar se necesitaría más casilleros hacia...
// arriba de los que hay, terminar análisis:
// trace ("No hay suficientes cuadraditos arriba");
break;
}
PunteroDeColumna = DesdeColumna;
PunteroDeFila = DesdeFila;
// trace ("Comenzando chequeo desde columna "+DesdeColumna+" y fila "+DesdeFila);
// trace ("hasta columna "+HastaColumna+" y fila "+HastaFila);
// Puede cambiar:
Win = "Sí";
do {
CasilleroaMirar = PunteroDeFila*CasillerosPorFila+PunteroDeColumna;
// trace ("Chequando el casillero "+CasilleroaMirar);
if (Situacion[Action] != Situacion[CasilleroaMirar]) {
Win = "No";
DesdeColumna = PunteroDeColumna+1;
DesdeFila = PunteroDeFila-1;
break;
}
PunteroDeColumna++;
PunteroDeFila--;
} while (PunteroDeColumna<=HastaColumna);
} while (DesdeColumna<=ColumnaDelMarcado && Win == "No");
// trace("Win: "+Win);
}