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:

Ejemplos prácticos (O=humano, X=ordenador)

A B C
1 O -1 X
2 -1 O X
3 -1 -1 106
A B C
1 O 4 X
2 O X 5
3 105 O 4

Nota: este archivo usa la página de códigos 850, “MS-DOS Europeo occidental”.

3enraya_bas_cp850.txt
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