Avec les évènements actuels, je trouve du temps pour faire un peu d'activité informatique "vintage".
Je découvre le IntyBasic, un langage crée par Oscar Todelo pour développer des programmes sur Intellivision. Son livre 'Programming games for Intellivision' est très bien et je conseille son achat. Il est en anglais mais ç'est pas trop difficile à comprendre.
C'est très sympa de découvrir l'univers de développement sur cette console (qui a eu beaucoup de succès aux USA). Ce Basic est simple, évolué et puissant (il peut intégrer des routines assembleur directement).
Ce que je trouve d'autant plus intéressant est de se retrouver confronté à des difficultés d'optimisation de code car la mémoire est très limitée.
On est loin de la programmation objet avec des structures complexes et des templates On apprend donc à faire du code construit différemment et le plus économe possible.
Par exemple, pour la création des symboles j'ai du optimisé car on ne peut redéfinir que 64 symboles de 8 * 8 sur la console. On n'a aussi que 8 sprites utilisables mais pour ce jeu, j'ai juste le curseur de sélection donc ça va c'est large.
A priori, on a que deux types de variables : numérique 8 ou 16 bits (signée / non signée). Pour l'instant, j'ai pas trouvé comment coder des variables alphanumériques.
J'ai cherché comment afficher les 2 couleurs disponibles dans les symboles (cards) et le codage n'est pas évident. J'ai trouvé la solution sur le wiki d'intellivision très complet.
Il faut ajouter un masque en binaire car la 2ème couleur n'est pas codée en contigüe. En effet, les 4 bits sont séparés dans le codage : bits 9, 10, 12 et 13. Le bit 11 est à 1 pour les symboles GROM, 0 pour ceux rédefinis.
La programme fait 12 Ko en version rom. Je crois que c'est bon car il me semble que les cartouches Intellivision faisaient 16 Ko. A vérifier...
J'ai développé ce modeste jeu de Memory (MEMOR-INTV) pour me faire la main comme on dit.
Il y a un écran de démarrage (title_screen) pour régler les options du jeu :
memory à recherche de carte unique (game_mode = 1) ou par paires (game_mode = 2), 1 ou 2 joueurs (+ ordi), choix du niveau de jeu de l'ordi.
On fait 3 parties d'affilé avec un cumul des scores puis on revient à l'écran d'accueil title_screen.
L'ordi - ou la console - choisit au hasard 9 ou 16 cartes constituées de 4 symboles graphiques puis les affiche à l'écran (temporairement).
Pour retourner une carte, on la choisit avec la manette (joueur 1 ou 2) en déplaçant le curseur graphique à l'écran, puis on valide son choix avec le bouton de la manette.
Sur PC, c'est au clavier bien sûr (joueur 1 : touches fléchées et touche shift droit pour valider).
L'IA est variable suivant le niveau de difficulté choisi. J'ai essayé de faire une IA correcte sans être exceptionnelle. Elle se base sur le nombre de fois que la carte a été retournée.
J'espère que ce premier programme ne bogue pas trop
Voici le code du jeu pour ceux que ça pourrait intéresser :
Code : Tout sélectionner
' =========================================================================
' IntyBASIC SDK Project: memory simple / pairs cards
' -------------------------------------------------------------------------
' Programmer: [PPJ]
' Created: 03/08/2020
' Updated: 03/08/2020
'
' Project automatically generated by INTYNEW.
' -------------------------------------------------------------------------
' History:
' 03/08/2020 - memory project created.
' =========================================================================
CLS
MODE 1
WAIT
DEFINE 0,16,screen_bitmaps_0
WAIT
DEFINE 16,4,screen_bitmaps_1
WAIT
DEFINE 21,1,cursor
init_game:
DIM memo(16*4)
DIM memo_s(16)
DIM memo_ia(16)
CONST HARD = 1
CONST MIDDLE = 2
CONST EASY = 3
game_mode = 1
level = MIDDLE
time_turn = 14
control_tempo = 5
nb_players = 1
first_player = 1
cycle = 3
DIM #scores(3)
DIM #selections(2)
DIM menu_values(3)
SIGNED winner
title_screen:
CLS
FOR x = 0 TO 24
PRINT AT x COLOR 6, " MEMOR-INTV"
WAIT
NEXT x
ptm = 0
ptm_old = ptm
min = get_range(ptm * 2): max = get_range(ptm * 2 + 1)
menu_values(0) = game_mode
menu_values(1) = level
menu_values(2) = nb_players
PRINT AT 201 COLOR 2, "PRESS START BUTTON"
DO
IF ptm = 0 THEN PRINT AT 63 COLOR $0203, "MODE ?" ELSE PRINT AT 63 COLOR 3, "MODE ?"
IF ptm = 1 THEN PRINT AT 103 COLOR $0203, "LEVEL ?" ELSE PRINT AT 103 COLOR 3, "LEVEL ?"
IF ptm = 2 THEN PRINT AT 143 COLOR $0203, "PLAYERS ?" ELSE PRINT AT 143 COLOR 3, "PLAYERS ?"
c = CONT1 AND $E0
IF (c = $A0) + (c = $C0) + (c = $60) THEN
validate = 1
ELSE
FOR i = 1 TO control_tempo
WAIT
NEXT i
IF CONT1.left AND menu_values(ptm) > min THEN menu_values(ptm) = menu_values(ptm) - 1: GOSUB sound_cursor
IF CONT1.right AND menu_values(ptm) < max THEN menu_values(ptm) = menu_values(ptm) + 1: GOSUB sound_cursor
IF CONT1.up AND ptm > 0 THEN ptm = ptm - 1
IF CONT1.down AND ptm < 2 THEN ptm = ptm + 1
if ptm <> ptm_old THEN
GOSUB sound_cursor
min = get_range(ptm * 2): max = get_range(ptm * 2 + 1)
ptm_old = ptm
END IF
END IF
IF menu_values(0) = 1 THEN PRINT AT 72 COLOR 3, "SIMPLE" ELSE PRINT AT 72 COLOR 3, "TWICE "
IF menu_values(1) = 1 THEN PRINT AT 113 COLOR 3, "HARD "
IF menu_values(1) = 2 THEN PRINT AT 113 COLOR 3, "MIDDLE"
IF menu_values(1) = 3 THEN PRINT AT 113 COLOR 3, "EASY "
PRINT AT 155 COLOR 3, <>menu_values(2)
LOOP WHILE validate = 0
GOSUB sound_cursor
game_mode = menu_values(0)
level = menu_values(1)
nb_players = menu_values(2) + 1
IF game_mode = 1 THEN
n_cards = 9
tab = n_cards / 3
offset_x = 2
offset_y = 2
delay = 50
ELSE
n_cards = 16
tab = n_cards / 4
offset_x = 1
offset_y = 0
delay = 75
END IF
start_game:
CLS
FOR i = 0 TO game_mode
#selections(i) = -1
NEXT i
PRINT AT 19 COLOR 2,<>(4 - cycle)
n_player = 0
selection = 0
attempt = 0
finished = 0
FOR n = 0 TO n_cards - 1 STEP game_mode
DO
m = RANDOM(3)
FOR c = 0 TO m
WAIT
NEXT c
FOR j = 0 TO 3
memo(n * 4 + j) = RANDOM(16)
IF game_mode = 2 THEN memo((n + 1) * 4 + j) = memo(n * 4 + j)
NEXT j
IF n > 1 THEN
v = n * 4
nok = 0
FOR k = 0 TO n - 1
w = k * 4
GOSUB card_equal
IF test = 1 THEN nok = 1: EXIT FOR
NEXT k
END IF
LOOP WHILE nok = 1
NEXT n
FOR n = 0 TO n_cards - 1
GOSUB hide_card
memo_ia(n) = 0
memo_s(n) = 0
IF game_mode = 2 THEN
m = RANDOM(n_cards)
IF m <> n THEN
FOR j = 0 TO 3
tmp = memo(m * 4 + j)
memo(m * 4 + j) = memo(n * 4 + j)
memo(n * 4 + j) = tmp
NEXT j
END IF
END IF
NEXT n
GOSUB update_scores
GOSUB guess_view_cards
n_player = first_player - 1
GOSUB turn_player
GOSUB card_choice
ON FRAME GOSUB play_sound
selection = 0
selection_old = -1
GOSUB show_cursor
loop_game:
IF n_player <> 2 THEN
IF n_player = 1 THEN c = CONT1 AND $E0 ELSE c = CONT2 AND $E0
IF (c = $A0) + (c = $C0) + (c = $60) THEN
' fire button
validate = 1
ELSE
validate = 0
FOR i = 1 TO control_tempo
WAIT
NEXT i
IF sounding = 0 THEN
selection_old = selection
IF n_player = 1 THEN
IF CONT1.left AND sx > 0 THEN selection = selection - 1
IF CONT1.right AND sx < tab - 1 THEN selection = selection + 1
IF CONT1.up AND sy > 0 THEN selection = selection - tab
IF CONT1.down AND sy < tab - 1 THEN selection = selection + tab
ELSE
IF CONT2.left AND sx > 0 THEN selection = selection - 1
IF CONT2.right AND sx < tab - 1 THEN selection = selection + 1
IF CONT2.up AND sy > 0 THEN selection = selection - tab
IF CONT2.down AND sy < tab - 1 THEN selection = selection + tab
END IF
IF selection <> selection_old THEN
selection_old = selection
GOSUB show_cursor
sounding = 1
END IF
END IF
END IF
ELSE
IF attempt > 0 THEN
FOR d = 0 TO delay
WAIT
NEXT d
END IF
IF attempt = 0 THEN target = choice ELSE target = choice2
IF memo_ia(target) > level AND RANDOM(10) > (level * 3 - 2) THEN
selection = target
ELSE
DO
nok = 0
selection = RANDOM(n_cards)
IF selection = selection_old AND total_found < n_cards - game_mode THEN nok = 1
LOOP WHILE memo_s(selection) = 1 OR nok = 1
END IF
validate = 1
GOSUB show_cursor
FOR d = 1 TO delay
WAIT
NEXT d
END IF
IF validate = 1 THEN
IF memo_s(selection) = 0 THEN
validate = 0
sounding = 2
GOSUB save_selection
IF attempt = game_mode THEN
GOSUB check_choice
IF ok = game_mode THEN sounding = 3 ELSE sounding = 4
ELSE
n = selection
GOSUB show_card
END IF
END IF
ELSE
GOSUB update_chrono
IF chrono_end = 1 THEN
chrono_end = 0
sounding = 4
tick = 0
ELSE
IF tick = 1 THEN tick = 0 : sounding = 5
END IF
END IF
GOTO loop_game
the_end:
SPRITE 0, 0
tick = 0
winner = 0
FOR s = 0 TO nb_players - 1
IF #scores(s) > #scores(winner) THEN winner = s
NEXT s
FOR s = 0 TO nb_players - 1
IF s <> winner AND #scores(s) = #scores(winner) THEN winner = -1: EXIT FOR
NEXT s
IF winner = -1 THEN
PRINT AT 80 COLOR 2," "
PRINT AT 100 COLOR 2," IT'S DUAL "
PRINT AT 120 COLOR 2," "
ELSE
PRINT AT 80 COLOR 2," "
PRINT AT 100 COLOR 2," WINNER: P",<>(winner + 1)," "
PRINT AT 120 COLOR 2," "
END IF
FOR i = 0 TO 3
#backtab(182 - game_mode + 20 * (i / 2) + 15 + i % 2) = 0
NEXT i
FOR i = 0 TO 25
WAIT
NEXT i
PRINT AT 201 COLOR 2, "PRESS START BUTTON"
cycle = cycle - 1
IF cycle > 0 THEN PRINT AT 221 COLOR 2, " TO CONTINUE GAME " ELSE PRINT AT 221 COLOR 2, " TO RETURN MENU "
DO
WAIT
c = CONT1
LOOP WHILE c
DO
WAIT
c = CONT1
LOOP WHILE c = 0
GOSUB sound_cursor
IF cycle > 0 THEN GOTO start_game ELSE GOTO title_screen
play_sound: PROCEDURE
ON sounding GOSUB stop_sounds, sound_cursor, sound_card, sound_good, sound_bad, sound_tick
END
stop_sounds: PROCEDURE
sound 0,,0
sound 1,,0
snd0 = 0
snd = 0
END
sound_cursor: PROCEDURE
SOUND 0, 100, 8
snd0 = snd0 + 1
IF snd0 = 3 THEN sounding = 0
END
sound_card: PROCEDURE
SOUND 0, 200 - snd * 10, 10
snd = snd + 1
IF snd = 8 THEN sounding = 0
END
sound_good: PROCEDURE
SOUND 1, 254 - snd * 5, 15 - snd
snd = snd + 1
IF snd = 15 THEN sounding = 0
END
sound_bad: PROCEDURE
SOUND 1, 1000 + (snd / 4 % 2) * 500, 10
snd = snd + 1
IF snd = 30 THEN sounding = 0
END
sound_tick: PROCEDURE
SOUND 1, 25, 8
snd = snd + 1
IF snd = 3 THEN sounding = 0
END
save_selection: PROCEDURE
nok = 0
IF #selections(attempt) = -1 THEN
IF game_mode > 1 THEN
FOR s = 0 TO game_mode - 1
IF #selections(s) = selection THEN nok = 1
NEXT s
END IF
IF nok = 0 THEN
#selections(attempt) = selection
IF selection = choice OR selection = choice2 THEN memo_ia(selection) = memo_ia(selection) + 1
attempt = attempt + 1
END IF
END IF
END
reset_selections: PROCEDURE
IF attempt > 0 THEN
attempt = 0
FOR s = 0 TO game_mode - 1
n = #selections(s)
IF show = 0 THEN GOSUB hide_card
#selections(s) = -1
attempt = 0
NEXT s
END IF
END
update_scores: PROCEDURE
offset = (3 - nb_players) * 20
pp = 1
FOR p = 1 TO nb_players
IF p = n_player THEN c = 6: d = 1 ELSE c = 1: d = 0
PRINT AT p * 60 - 46 + offset, " "
IF p = 2 THEN PRINT AT p * 60 - 46 + offset + d COLOR c,"INTV: " ELSE PRINT AT p * 60 - 46 + offset + d COLOR c,"P",<>pp,": " : pp = pp + 1
IF p = n_player THEN c = 7 ELSE c = 3
PRINT AT p * 60 - 26 + offset, " "
PRINT AT p * 60 - 26 + offset + d COLOR c,<4>#scores(p - 1)
NEXT p
WAIT
END
update_chrono: PROCEDURE
IF chrono > 0 THEN
IF laps_chrono > 0 THEN
laps_chrono = laps_chrono - 1
ELSE
chrono = chrono - 1
IF chrono < 5 THEN tick = 1
laps_chrono = 8
IF chrono = 0 THEN
GOSUB turn_player
chrono_end = 1
ELSE
GOSUB draw_chrono
END IF
END IF
END IF
END
draw_chrono: PROCEDURE
IF chrono = 0 THEN RETURN
FOR c = 0 TO chrono
zz = 240 - c * 20 + 12
IF chrono < 5 THEN c2 = 2 ELSE c2 = 4
IF c < chrono THEN #backtab(zz) = $0800 + 2 * 8 + c2 ELSE #backtab(zz) = 0
NEXT c
END
turn_player: PROCEDURE
sounding = 0
chrono = time_turn
laps_chrono = 8
GOSUB draw_chrono
show = 0
GOSUB reset_selections
IF n_player < nb_players THEN
n_player = n_player + 1
ELSE
n_player = 1
END IF
GOSUB update_scores
END
card_choice: PROCEDURE
total_found = 0
FOR c = 0 TO n_cards - 1
total_found = total_found + memo_s(c)
NEXT c
IF total_found = n_cards THEN finished = 1:RETURN
DO
choice = RANDOM(n_cards)
LOOP WHILE memo_s(choice) = 1
choice2 = 0
IF game_mode = 2 THEN
FOR i = 0 TO n_cards - 1
IF i <> choice THEN
v = i * 4
w = choice * 4
GOSUB card_equal
IF test = 1 THEN choice2 = i: EXIT FOR
END IF
NEXT i
END IF
FOR i = 0 TO 3
z = memo(choice * 4 + i)
#backtab(182 - game_mode + 20 * (i / 2) + 15 + i % 2) = get_ink(z) + $0800 + z * 8 + 7
NEXT i
END
card_equal: PROCEDURE
test = 0
IF memo(w) = memo(v) AND memo(w + 1) = memo(v + 1) \
AND memo(w + 2) = memo(v + 2) AND memo(v + 3) = memo(w + 3) THEN test = 1
END
check_choice: PROCEDURE
n = selection
GOSUB show_card
ok = 0
FOR s = 0 TO game_mode - 1
IF #selections(s) = choice THEN
ok = ok + 1
ELSE
v = #selections(s) * 4
w = choice * 4
GOSUB card_equal
IF test = 1 THEN ok = ok + 1
END IF
NEXT s
FOR i = 0 TO delay + 25
WAIT
NEXT i
IF ok = game_mode THEN
#scores(n_player - 1) = #scores(n_player - 1) + (chrono * 2 - (total_found / game_mode)) * 5 * game_mode
IF #scores(n_player - 1) > 9999 THEN #scores(n_player - 1) = 9999
GOSUB card_choice
GOSUB update_scores
IF finished = 1 THEN sounding = 5: GOTO the_end
show = 1
GOSUB reset_selections
chrono = time_turn
laps_chrono = 8
GOSUB update_chrono
ELSE
#scores(n_player - 1) = #scores(n_player - 1) - chrono * (game_mode - ok)
IF #scores(n_player - 1) < 0 THEN #scores(n_player - 1) = 0
GOSUB turn_player
END IF
END
show_cursor: PROCEDURE
sy = selection / tab
sx = selection % tab
x_cursor = sx * 24 + offset_x * 8 + 20
y_cursor = sy * 24 + offset_y * 8 + 20
SPRITE 0,$0300 + x_cursor, $0100 + y_cursor, $0806 + 21 * 8
WAIT
END
show_card: PROCEDURE
line = n / tab
column = n % tab
FOR i = 0 TO 3
z = memo(n * 4 + i)
#backtab(line * 60 + 20 * (i / 2) + column * 3 + i % 2 + offset_x + offset_y * 20) = get_ink(z) + $0800 + z * 8 + 7
NEXT i
memo_s(n) = 1
memo_ia(n) = memo_ia(n) + 1
END
hide_card: PROCEDURE
line = n / tab
column = n % tab
FOR i = 0 TO 3
#backtab(line * 60 + 20 * (i / 2) + column * 3 + i % 2 + offset_x + offset_y * 20) = $0800 + (16 + i) * 8 + 2
NEXT i
memo_s(n) = 0
END
hide_all_cards: PROCEDURE
FOR n = 0 TO n_cards - 1
GOSUB hide_card
NEXT n
END
guess_view_cards: PROCEDURE
t = 0
FOR d = 0 TO delay
WAIT
NEXT d
DO
DO
n = RANDOM(n_cards)
LOOP WHILE memo_s(n) = 1
GOSUB show_card
a = RANDOM(4)
IF a > level THEN memo_ia(n) = memo_ia(n) + 1
t = t + 1
FOR d = 0 TO delay
WAIT
NEXT d
LOOP WHILE t < n_cards
FOR d = 0 TO delay * 3
WAIT
NEXT d
GOSUB hide_all_cards
END
get_range:
DATA 1, 2, 1, 3, 1, 2
get_ink:
' get background color (0-15)
DATA &0000000000000000,&0000001000000000,&0000010000000000,&0000011000000000,&0001000000000000,&0001001000000000,&0001010000000000,&0001011000000000
DATA &0010000000000000,&0010001000000000,&0010010000000000,&0010011000000000,&0011000000000000,&0011001000000000,&0011010000000000,&0011011000000000
cursor:
BITMAP "XXXXXX.."
BITMAP "XXXXX..."
BITMAP "XXXX...."
BITMAP "XXXXX..."
BITMAP "XX.XXX.."
BITMAP "X...XXX."
BITMAP ".....XX."
BITMAP "........"
screen_bitmaps_0:
DATA $FFFF,$FFFF,$FFFF,$FFFF
DATA $FFFF,$C3C3,$C3C3,$FFFF
DATA $0000,$3C3C,$3C3C,$0000
DATA $E7FF,$81E7,$E781,$FFE7
DATA $A5FF,$81A5,$A581,$FFA5
DATA $99FF,$C381,$81C3,$FF99
DATA $81FF,$81E7,$E781,$FF81
DATA $C3FF,$A5BD,$B5A5,$FFC7
DATA $BDFF,$C399,$99C3,$FFBD
DATA $99FF,$FFBD,$BDFF,$FF99
DATA $3333,$CCCC,$3333,$CCCC
DATA $0000,$FFFF,$0000,$FFFF
DATA $3333,$3333,$3333,$3333
DATA $E7FF,$81C3,$9981,$FF99
DATA $99FF,$8199,$E7C3,$FFE7
DATA $81FF,$81A5,$DB81,$FFE7
screen_bitmaps_1:
DATA $7F00,$4340,$4C47,$0048
DATA $FE00,$C202,$72E2,$E072
DATA $4100,$4041,$4041,$007F
DATA $82C0,$0282,$0282,$00FE
DATA $FFFF,$FF00,$00FF,$FFFF