Flash, Inteligencia Artificial + 3 en raya
Hoy les presento a un juego que tiene mucha historia.
Esta vez, el juego lo he construido yo, de arriba a abajo. ![]()
Tiene 2 tipos de juego: Dos Jugadores, para jugar 2 personas desde el mismo PC; y Un Jugador, contra la Inteligencia Artificial que programé.
Nota: La inteligencia Artificial buena, es la de nivel 3 U_U
Algunas referencias para entender el código:
Para trabajar mejor con el tablero, lo representé virtualmente como una matriz 3×3:
[as]var t:Array = new Array();
t = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];[/as]
Cuando una posición del tablero (matriz) esta vacía, (no ha sido ocupada) le asigno un valor de 0.
Cuando una posición del tablero (matriz) ha sido ocupada por una cruz, le doy valor -1.
Cuando una posición del tablero (matriz) ha sido ocupada por una circunferencia, le doy valor 1.
Como podrán ver en el código de la IA, al trabajar con estos valores para la matriz, nos facilita mucho mas las cosas que trabajando con, por ejemplo: undefined , true y false
Les pongo el código de la IA con las funciones que utiliza:
[as]stop();
restart();
//–>Game
function evaluar(t) {
var res:Number = 0;
if (t[0][0] == t[1][1] && t[1][1] == t[2][2]) {
res = t[0][0];
}
if (t[0][2] == t[1][1] && t[1][1] == t[2][0]) {
res = t[0][2];
}
if (t[0][0] == t[0][1] && t[0][1] == t[0][2]) {
res = t[0][0];
}
if (t[1][0] == t[1][1] && t[1][1] == t[1][2]) {
res = t[1][0];
}
if (t[2][0] == t[2][1] && t[2][1] == t[2][2]) {
res = t[2][0];
}
if (t[0][0] == t[1][0] && t[1][0] == t[2][0]) {
res = t[0][0];
}
if (t[0][1] == t[1][1] && t[1][1] == t[2][1]) {
res = t[0][1];
}
if (t[0][2] == t[1][2] && t[1][2] == t[2][2]) {
res = t[0][2];
}
return res;
}
function posicion_libre(t) {
var res:Boolean = false;
var i:Number = 0;
var j:Number = 0;
for (i=0; i<3; i++) {
for (j=0; j<3; j++) {
if (t[i][j] == 0) {
res = true;
}
}
}
return res;
}
function disable() {
for (i=0; i<3; i++) {
for (j=0; j<3; j++) {
_root["_"+i+"_"+j].enabled = false;
}
}
}
function cruz(i, j) {
_root["_"+i+"_"+j].gotoAndStop("cruz");
t[i][j] = -1;
turno = 1;
turno_mc.gotoAndStop("p1");
trace(i+","+j);
}
function circulo(i, j) {
_root["_"+i+"_"+j].gotoAndStop("circulo");
t[i][j] = 1;
turno = 2;
turno_mc.gotoAndStop("p2");
}
function pulsar(i, j) {
if (!fin) {
if (turno == 1) {
circulo(i,j);
if (evaluar(t) == 0) {
IA();
}
}
}
switch (evaluar(t)) {
case 0 :
if (!posicion_libre(t)) {
//trace("empate");
turno_mc.gotoAndStop("empate");
reiniciar.play();
fin = true;
disable();
}
break;
case -1 :
//trace("ganan cruzes");
turno_mc.gotoAndStop("cruces");
reiniciar.play();
fin = true;
disable();
break;
case 1 :
//trace("ganan criculos");
turno_mc.gotoAndStop("circulos");
reiniciar.play();
fin = true;
disable();
break;
default :
trace("OMG! GRAN ERROR!");
break;
}
}
function restart() {
turno = 1;
fin = false;
turno_mc.gotoAndStop("p1");
for (i=0; i<3; i++) {
for (j=0; j<3; j++) {
_root["_"+i+"_"+j].enabled = true;
_root["_"+i+"_"+j].gotoAndStop(1);
t[i][j] = 0;
}
}
}
_0_0.onPress = function() {
pulsar(0,0);
};
_0_1.onPress = function() {
pulsar(0,1);
};
_0_2.onPress = function() {
pulsar(0,2);
};
_1_0.onPress = function() {
pulsar(1,0);
};
_1_1.onPress = function() {
pulsar(1,1);
};
_1_2.onPress = function() {
pulsar(1,2);
};
_2_0.onPress = function() {
pulsar(2,0);
};
_2_1.onPress = function() {
pulsar(2,1);
};
_2_2.onPress = function() {
pulsar(2,2);
};
reiniciar.onPress = function() {
restart();
if (cont) {
reiniciar.play();
}
};
menu.onPress = function() {
gotoAndStop("tablero");
};
/*----------I A ------------*/
function IA() {
var fet:Boolean = false;
var a:Number = 0;
var b:Number = 0;
if (d != 1 && d != 2) {//si no es facil ni normal
if (t[1][1] == 0 && !fet) {//coloca el medio
cruz(1,1);
fet = true;
}
if (!fet) {
a = 0;
for (i=0; i<3; i++) {
for (j=0; j<3; j++) {
if (t[i][j] == 0) {
a++;
}
}
}
if (a == 8 && (t[0][0] == 0 || t[2][0] == 0 || t[0][2] == 0 || t[2][2] == 0)) {
b = Math.floor(Math.random()*3);
switch (b) {
case 0 :
if (t[0][0] == 0 && !fet) {
cruz(0,0);
fet = true;
}
break;
case 1 :
if (t[0][2] == 0 && !fet) {
cruz(0,2);
fet = true;
}
break;
case 2 :
if (t[2][0] == 0 && !fet) {
cruz(2,0);
fet = true;
}
break;
case 3 :
if (t[2][2] == 0 && !fet) {
cruz(2,2);
fet = true;
}
break;
default :
trace("Error Switch");
break;
}
}
}
//a partir de aquí ataca->>>>>>
if (d != 1) {// si no es fácil (normal)
if (((t[0][0])+(t[1][1])+(t[2][2])) == -2 && !fet) {// diagonal 1 (\)
for (a=0; a<3; a++) {
b = a;//equación (condición de los puntos para que pertenezcan) a la recta de la diagonal 1 (y=x)
if (t[a][b] == 0 && !fet) {
cruz(a,b);
fet = true;
}
}
}
if (((t[0][2])+(t[1][1])+(t[2][0])) == -2 && !fet) {//diagonal 2 (/)
for (a=0; a<3; a++) {
b = 2-a;
if (t[a][b] == 0 && !fet) {
cruz(a,b);
fet = true;
}
}
}
b = 0;
while (b<3 && !fet) {
if (((t[0][b])+(t[1][b])+(t[2][b])) == -2 && !fet) {//horitzontals
for (a=0; a<3; a++) {
if (t[a][b] == 0 && !fet) {
cruz(a,b);
fet = true;
}
//endif
}//endfor
}
//endifyelse
b++;
}//endwhile
a = 0;
while (a<3 && !fet) {
if (((t[a][0])+(t[a][1])+(t[a][2])) == -2 && !fet) {
for (b=0; b<3; b++) {
if (t[a][b] == 0 && !fet) {
cruz(a,b);
fet = true;
}
}
}
a++;
}//endwhile
//a partir de aquí se defiende->>>>>>
if (Math.abs((t[0][0])+(t[1][1])+(t[2][2])) == 2 && !fet) {// diagonal 1 (\)
for (a=0; a<3; a++) {
b = a;//equación (condición de los puntos para que pertenezcan) a la recta de la diagonal 1 (y=2-x)
if (t[a][b] == 0 && !fet) {
cruz(a,b);
fet = true;
}
}
}
if (Math.abs((t[0][2])+(t[1][1])+(t[2][0])) == 2 && !fet) {//diagonal 2 (/)
for (a=0; a<3; a++) {
b = 2-a;
if (t[a][b] == 0 && !fet) {
cruz(a,b);
fet = true;
}
}
}
b = 0;
while (b<3 && !fet) {
if ((Math.abs((t[0][b])+(t[1][b])+(t[2][b]))) == 2 && !fet) {//horitzontals
for (a=0; a<3; a++) {
if (t[a][b] == 0 && !fet) {
cruz(a,b);
fet = true;
}
//endif
}//endfor
}
//endifyelse
b++;
}//endwhile
a = 0;
while (a<3 && !fet) {
if (Math.abs((t[a][0])+(t[a][1])+(t[a][2])) == 2 && !fet) {
for (b=0; b<3; b++) {
if (t[a][b] == 0 && !fet) {
cruz(a,b);
fet = true;
}
}
}
a++;
}//endwhile
}
//acaba el ataque+defensa (no hay posibliidad de ganar o perder)
}
if (!fet) {
a = 0;
for (i=0; i<3; i++) {
for (j=0; j<3; j++) {
if (t[i][j] == 0) {
a++;
}
}
}
if (a == 6 && (t[0][1] + t[1][0] + t[1][2] + t[2][1] == 0)) {
b = Math.floor(Math.random()*3);
switch (b) {
case 0 :
if (t[0][1] == 0 && !fet) {
cruz(0,1);
fet = true;
}
break;
case 1 :
if (t[1][0] == 0 && !fet) {
cruz(1,0);
fet = true;
}
break;
case 2 :
if (t[1][2] == 0 && !fet) {
cruz(1,2);
fet = true;
}
break;
case 3 :
if (t[2][1] == 0 && !fet) {
cruz(2,1);
fet = true;
}
break;
default :
trace("Error Switch 2");
break;
}
}
while (a == 6 && (t[0][0] + t[0][2] + t[2][0] + t[2][2] == 1) && !fet) {
b = Math.floor(Math.random()*3);
switch (b) {
case 0 :
if (t[0][0] == 0 && !fet) {
cruz(0,0);
fet = true;
}
break;
case 1 :
if (t[0][2] == 0 && !fet) {
cruz(0,2);
fet = true;
}
break;
case 2 :
if (t[2][0] == 0 && !fet) {
cruz(2,0);
fet = true;
}
break;
case 3 :
if (t[2][2] == 0 && !fet) {
cruz(2,2);
fet = true;
}
break;
default :
trace("Error Switch");
break;
}
}
}
//end dificultad
//no hay 2 iguales: (Genera una posición aleatoria)
if (!fet) {
for (i=0; i<3; i++) {
for (j=0; j<3; j++) {
if (t[i][j] == 0 && !fet) {
cruz(i,j);
fet = true;
}
}
}//endfors
}
}//endIA
[/as]
Como verán es algo lioso ver solamente el código, con lo que aquí les dejo el link para descargarlo:
Descargar 3 en raya (Código fuente *.fla)
Espero, les pueda ayudar en algo.
Me costó bastantes horas encontrar los bugs de la IA y perfeccionarla.
La IA no es perfecta, aunque tiene un buen nivel U_U
Entradas Relacionadas:
Vale, la IA ha sido owneada… 2 veces… (ni 30 minutos me dejan vivir en la felicidad)
Gané!!
Ya te lo he dicho por gtalk
Muy bueno Bleend (y)
Jugué aproximadamente 5 veces, en el nivel 3, pero siempre hubo empate, no me dejó ganar ¬¬ Pero yo tampoco la dejé XD
Prueba hacerlo en Prolog XD
Si anda, como dice takag, prueba hacerlo en algún “Facíl y legible” lenguaje de programación lógica… el año que termines me avisas XD
Aunque claro, creo que el paradigma se aplica a este problema.
Es curioso, las formas para ganarle son las mismas que usaban mis amigos y yo para ganar entre nosotros XD
Este……………..
este…………
YA!
Creo que se puede hacer muchísimo más corto ese código.
Modo: Coges una matriz y le pones los 9*12 posibles movimientos con giros y simetrias. en cada turno buscas en la matriz donde este esa secuencia y te da la respuesta de movimiento.
Lo que es el algoritmo de IA…..3 lineas de código.
Sin acritud. Buen ejercicio.
Buf… Teseo, tu eres el amo; yo paso como puedo…
xD n ose como llegue aqui..
..
bueno le gane
(crusas el centro, luego la esquina contraria que marque la IA.. y luego ganas… XD.. facil)
hmm y como dice teseo.. el codigo se puede hacer en mucho mucho menos codigo..
suerte ^^
hmm bueno .. segui probando.. y si.. como les digo.. siempre ganas.. NUNCA PIERDES..
esplico denuevo: marcas el centro.. (luego el marca una esquina), tu amrcas la esquina contraria (luego el te tapa o pone nseguida de la priemra q puso).. luego tu lo tapas… y te quedan algo asi: al centro… y 2 abajo. una en cada esquina.. luego el te tapa… y luego ganas… xD
suerte y ganenle mucho ^^
Gracias Muela, sí, efectivamente, la IA no es dios que digamos…. *sigh
De todas formas ahí se queda, no voy a arreglarla.
Si buscan una perfecta, HernanRivas publicó una en cristalab.
huevada
que bueno tu juego
La partida perfecta acaba en empate.
Siempre he estado probando combinaciones nuevas para ganar a mi hermano y contra el funcionan pero me he dado cuenta de que a mi mismo por ejemplo no podria ganarme
En que version esta guardado el .fla??
No me deja abrirlo con el flash 8, me sale que el archivo es corrupto :S
Prueba con el CS3.
grax muy valioso tu aporte pz xD