====Tres en raya para basic (Gwbasic, compatible con qbasic y qb64) ==== El tres en raya es un juego cuyo análisis es muy simple; por eso fue uno de los primeros (y casi el único) para los que me sentí capaz de elaborar un "autómata" capaz de jugar contra el humano. ===Estrategia del jugador robot=== El "cerebro" del juego, en las líneas 400-750, se puede dividir en dos partes: *En primer lugar (líneas 440-460), el ordenador "suma" el número de piezas en cada una de las líneas. La ubicación de cada una de las tres casillas de cada línea ha sido previamente recuperada de unas instrucciones DATA en 1000-1080 y almacenada en la matriz LINEAS. La primera dimensión representa el número de línea (ocho en total), la segunda indica la casilla (primera, segunda o tercera) de la línea y la tercera indica si estamos pidiendo la coordenada X o Y. *En segundo lugar, el ordenador "sube" o "baja" el valor de cada casilla de la línea según el número de piezas en la línea: *Si hay dos piezas del ordenador (-2), se asigna un valor muy alto (+85) a las casillas de la línea, pues "ganar" es mejor que "evitar perder". *Si hay dos piezas del humano (2), se asigna un valor alto (+21), para que "evitemos perder". *Si hay una pieza nuestra, y ninguna del humano, en la línea, (-1), se asigna un valor alto (+5), pero no tanto como para que una pieza con tres líneas vacías a su alrededor valga más que una amenaza real del jugador humano. *Por último, si hay una pieza del humano aislada en una línea, reducimos el valor de esa casilla (-1), pero no tanto como para disimular una amenaza real en esa casilla. Ejemplos prácticos (O=humano, X=ordenador) ^ ^ A ^ B ^ C | ^ 1| O | -1 | X | ^ 2| -1 | O | X | ^ 3| -1 | -1 | 106 | *//C3 vale 85+21+0=106, porque la columna C1..C3 tiene dos fichas del ordenador (+85), hay una amenaza humana en la diagonal (+21), y no hay fichas en la fila C3:C3 .// ^ ^ A ^ B ^ C | ^ 1| O | 4 | X | ^ 2| O | X | 5 | ^ 3| 105 | O | 4 | *//A3 vale 85+21-1=105, porque la línea diagonal tiene dos fichas del ordenador (+85), hay una amenaza human en la columna A1:A3 (+21), y hay la fila horizontal A3:C3 solo está ocupada por una ficha humana.// *//C2 vale 5+0=5. La columna C1:C2 tiene solo una ficha del ordenador (+5), y hay tanto una ficha del ordenador como una humana en la fila A2:C2 (+0).// *//C3 vale 5-1=0. Está en la misma columna que C2 (+5), pero la presencia de una pieza humana solitaria en la fila A3:C3 reduce su valor (-1).// Nota: este archivo usa la página de códigos 850, "MS-DOS Europeo occidental". 5 RANDOMIZE VAL(MID$(TIME$, 7)) 10 REM ***** Tres en raya ***** 20 CLS: SCREEN 1 30 DIM TABLERO(3, 3): DIM VALORCASILLA(3, 3) 40 DIM LINEAS(8, 3, 2): DIM MEJORMOVIMIENTO(9, 2) 50 RESTORE 1000 60 FOR A = 1 TO 8: FOR B = 1 TO 3 70 READ LINEAS(A, B, 1), LINEAS(A, B, 2) 80 NEXT: NEXT 90 LINE (150, 20)-(150, 80): LINE (170, 20)-(170, 80): LINE (130, 40)-(190, 40): LINE (190, 60)-(130, 60) 100 REM ***** Inicio del juego ***** 110 MOVIMIENTOS = 0 120 VIEW PRINT 16 TO 24: CLS 2: GOTO 5000 200 REM ***** Movimiento del jugador humano ***** 210 VIEW PRINT 16 TO 24: CLS 2 220 LOCATE 16, 1: INPUT "¨D¢nde mueves? (Se¤ala con una letra la columna)"; A$ 230 IF LEN(A$) <> 2 THEN PRINT "Coordenadas no v lidas": GOTO 210 240 A1$ = MID$(A$, 1, 1) 250 IF A1$ > "Z" THEN A1$ = CHR$(ASC(A1$) - 32) 260 IF A1$ > "C" OR A1$ < "A" THEN PRINT "Coordenadas horizontales v lidas de A a C": GOTO 210 270 X = ASC(A1$) + 1 - ASC("A") 280 A2$ = MID$(A$, 2, 1) 290 IF A2$ < "1" OR A2$ > "3" THEN PRINT "Coordenadas verticales v lidas de 1 a 3": GOTO 210 300 Y = VAL(A2$) 310 IF TABLERO(X, Y) <> 0 THEN PRINT "La casilla est  ocupada": GOTO 210 320 JUGADOR = 1: GOSUB 2000 330 TABLERO(X, Y) = 1 340 GOSUB 3000 350 MOVIMIENTOS = MOVIMIENTOS + 1: IF MOVIMIENTOS >= 9 THEN GOTO 4010 400 REM ***** movimiento del ordenador ***** 410 REM ***** Valoración de las líneas ***** 420 FOR F=1 TO 3:FOR G=1 TO 3:VALORCASILLA(F,G)=0:NEXT :NEXT 430 FOR A=1 TO 8:LINLLENA=0 440 FOR B=1 TO 3 450 LINLLENA=LINLLENA+TABLERO(LINEAS(A,B,1),LINEAS(A,B,2)) 460 NEXT 470 FOR B=1 TO 3 480 XL=LINEAS(A,B,1):YL=LINEAS(A,B,2) 490 IF LINLLENA=1 THEN VALORCASILLA(XL,YL)=VALORCASILLA(XL,YL)+1 500 IF LINLLENA=-1 THEN VALORCASILLA(XL,YL)=VALORCASILLA(XL,YL)+5 510 IF LINLLENA=2 THEN VALORCASILLA(XL,YL)=VALORCASILLA(XL,YL)+21 520 IF LINLLENA=-2 THEN VALORCASILLA(XL,YL)=VALORCASILLA(XL,YL)+85 530 NEXT 540 NEXT 550 MAXIMO=0:FOR A=1 TO 3:FOR B=1 TO 3 560 IF TABLERO(A,B)<>0 THEN VALORCASILLA(A,B)=-1 570 IF VALORCASILLA(A,B)>MAXIMO THEN MAXIMO=VALORCASILLA(A,B) 580 NEXT :NEXT 590 NUMMEJORES=0 600 FOR A=1 TO 3:FOR B=1 TO 3 610 IF VALORCASILLA(A,B)=MAXIMO THEN NUMMEJORES=NUMMEJORES+1:MEJORMOVIMIENTO(NUMMEJORES,1)=A:MEJORMOVIMIENTO(NUMMEJORES,2)=B 620 NEXT :NEXT 630 MOVIMIENTO=INT(RND*NUMMEJORES-1)+1 640 IF MOVIMIENTO=0 THEN PRINT"ERROR: Movimiento=0":MOVIMIENTO=1 650 IF MOVIMIENTO>9 THEN PRINT"ERROR: Movimiento>9":MOVIMIENTO=9 660 X=MEJORMOVIMIENTO(MOVIMIENTO,1) 670 Y=MEJORMOVIMIENTO(MOVIMIENTO,2) 680 IF MAXIMO<=4 AND TABLERO(2,2)=0 THEN X=2:Y=2 690 PRINT"Mi movimiento: ";CHR$(ASC("A")+X-1);Y 700 IF TABLERO(X,Y)<>0 THEN PRINT"Casilla ocupada":GOTO 630 710 JUGADOR =2 :GOSUB 2000 720 TABLERO(X,Y)=-1 730 GOSUB 3000 740 MOVIMIENTOS=MOVIMIENTOS+1:IF MOVIMIENTOS>=9 THEN GOTO 4010 750 GOTO 210 1000 REM datos de las lineas posibles 1010 DATA 1,1,1,2,1,3: REM horiz. 1 1020 DATA 2,1,2,2,2,3: REM horiz. 2 1030 DATA 3,1,3,2,3,3: REM horiz. 3 1040 DATA 1,1,2,1,3,1: REM vert. 1 1050 DATA 1,2,2,2,3,2: REM vert. 2 1060 DATA 1,3,2,3,3,3: REM vert. 3 1070 DATA 1,1,2,2,3,3: REM diag. 1 1080 DATA 3,1,2,2,1,3: REM diag. 2 2000 REM poner cruz/poner circulo 2010 IF JUGADOR = 1 THEN GOTO 2040 2020 CIRCLE (120 + 20 * X, 10 + 20 * Y), 10, 1 2030 RETURN 2040 LINE (110 + 20 * X, 20 * Y)-(130 + 20 * X, 20 + 20 * Y), 2 2050 LINE (110 + 20 * X, 20 + 20 * Y)-(130 + 20 * X, 20 * Y), 2 2060 RETURN 3000 REM ***** ¨Es tres en raya? ***** 3010 FOR A = 1 TO 8 3020 LINLLENA = 0: FOR B = 1 TO 3 3030 LINLLENA = LINLLENA + TABLERO(LINEAS(A, B, 1), LINEAS(A, B, 2)) 3040 NEXT 3050 IF LINLLENA = 3 THEN PRINT "Haces tres en raya": GOTO 4010 3060 IF LINLLENA = -3 THEN PRINT "Hago tres en raya": GOTO 4010 3070 NEXT 3080 RETURN 4000 REM ***** ¨Volver a jugar? ***** 4010 INPUT "¨Quieres volver a jugar?"; A$ 4020 IF MID$(A$, 1, 1) = "S" OR MID$(A$, 1, 1) = "s" THEN RUN 4030 IF MID$(A$, 1, 1) = "N" OR MID$(A$, 1, 1) = "n" THEN END 4040 PRINT "Responde 'S' o 'N'": GOTO 4010 5000 REM ***** Decidir qui‚n comienza ***** 5010 INPUT "1- Comienzo yo 2- Comienzas t£"; N 5020 IF N = 1 THEN GOTO 400 5030 IF N = 2 THEN GOTO 200 5040 GOTO 5000