Here again an Othello
(or Reversi) like game:
You can ply against the computer or against another player.
Here is the source code:
REBOL [
Title: "Reversi"
Date: 27-Mar-2006
Version: 2.3.0
File: %reversi.r
Author: "Vincent Ecuyer"
Purpose: "Reversi / Othello"
Usage: {
===English
Classic Reversi / Othello game.
It's a two players board game, where the objective is to cover the
board with the greatest number of pieces of your chosen color.
The first four pieces must be placed at the center of the plate,
then the normal game begins.
At each turn, each player puts a two faced piece on the board -
all adjacent opponent pieces between the new one and the ones on the
board are reversed to match the player color:
right after the start: after more turns: (two diagonals
(one horizontal line reversed) and one vertical lines reversed)
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . X . . . . . . . X . . . .
. . . . . . . . . . . . . . . . . . . X v X . . . . . X O X . .
. . . O X v . . > . . . O O O . . . . X X X X . . > . . X O O O . .
. . . X O . . . > . . . X O . . . . . X X X X O . > . . O X O X O .
. . . . . . . . . . . . . . . . . O O O O O X . . O O O O O X .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
If it doesn't reverse opponent pieces, you can't place a piece on the
board - you must skip your turn.
The game ends when the board is fully covered, or when both players
can't puts pieces on the plate anymore.
This script allows you to play against another player or a basic AI .
If the game starts in french, change the first code line from
language: 'francais
to
language: 'english
.
===Français
Le jeu Reversi, aussi appelé Othello.
C'est un jeu de plateau pour deux joueurs, où l'objectif est de
couvrir le plateau avec le plus grand nombre de pièces de votre
couleur.
Les quatre premières pièces doivent être placées sur les cases du
centre du plateau, puis la partie normale commence.
Dans un tour, chaque joueur place une pièce à deux faces sur le
plateau - toutes les pièces adjacentes de l'adversaire situées entre
la nouvelle pièce et les pièces déjà placées sont retournées pour
présenter la couleur du joueur:
juste après le début: plus tard dans la partie: (deux
(une ligne horizontale retournée)diagonales et une colonne retournées)
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . X . . . . . . . X . . . .
. . . . . . . . . . . . . . . . . . . X v X . . . . . X O X . .
. . . O X v . . > . . . O O O . . . . X X X X . . > . . X O O O . .
. . . X O . . . > . . . X O . . . . . X X X X O . > . . O X O X O .
. . . . . . . . . . . . . . . . . O O O O O X . . O O O O O X .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ....... ........
Vous devez retourner des pions de l'adversaire à chaque coup - si
c'est impossible vous passez votre tour.
La partie se termine lorsque le plateau est recouvert où lorsque aucun
joueur ne peut placer de pion.
Ce script vous permet de jouer contre un autre joueur où contre une
AI basique.
Pour jouer en français, changez la première ligne de code de
language: 'english
en
language: 'francais
.
}
Library: [
level: 'advanced
platform: 'all
type: 'game
domain: [gui vid game]
tested-under: [
view 1.3.2.3.1 on [Win2K]
view 1.2.1.1.1 on [AmigaOS30]
view 1.2.1.3.1 on [Win2K]
]
support: none
license: 'gpl
see-also: none
]
History: [
1.0.0 26-7-2001
"Première version jouable"
2.0.0 15-5-2002
"Première version publique. Refonte du moteur et ajout du niveau de difficulté"
2.1.0 2-2-2004
"Nettoyage du code pour View 1.3 et amélioration du redimensionnement."
2.2.0 28-1-2005
"Plus de libertés pour le redimensionnement."
2.3.0 27-3-2006
"Refonte de l'interface."
]
]
; ===Localisation
; choix de la langue/language selection (actuellement, 'francais ou 'english)
language: 'english
; textes de l'application
locale-strings: [
francais [
doc [
usage {
Le jeu commence en mode deux joueurs.
Le premier bouton indique le mode de jeu actuel,
et permet de le modifier.
Le second règle le niveau de difficulté:
- minimum : un des trois meilleurs coups trouvés est joué
- moyen : un des deux meilleurs coups trouvés est joué
- maximum : le meilleur coup trouvé est joué
}
usage-title "Utilisation"
usage-close "(cliquez sur la fenêtre pour la fermer)"
]
mode [
human-human "2 joueurs"
computer-white "Ordinateur joue blancs"
computer-black "Ordinateur joue noirs"
]
level [min "Minimum" med "Moyen" max "Maximum" ]
button [skip "Passer le tour" end "Fin de la partie" ]
score [
draw "Egalité"
white "Joueur blanc gagnant"
black "Joueur noir gagnant"
]
]
english [
doc [
usage {
The game starts in two players mode.
The leftmost button shows the current mode,
and allows to change it.
The second button controls difficulty:
- minimum : one of the three best moves is played
- medium : one of the two best moves is played
- maximum : the best move is played
}
usage-title "Usage"
usage-close "(click on this window to close it)"
]
mode [
human-human "2 Players"
computer-white "Computer plays light"
computer-black "Computer plays dark"
]
level [min "Minimum" med "Medium" max "Maximum" ]
button [skip "Skip turn" end "End game" ]
score [
draw "Draw game"
white "Light Wins"
black "Dark Wins"
]
]
]
; fonction de localisation
locale: func [
"Sélectionne la chaîne dans la langue courante."
'name [word! path!] "Nom de la chaîne"
/local r
][
r: locale-strings/:language
foreach i :name [r: r/:i]
]
; ===Aspect visuel
; motif de fond du plateau
; (ici, le motif %wood1.pat de GIMP, avec l'effet [colorize 170.100.70])
fond.png: load 64#{
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
/p0+lCkKJWo8AAAAASUVORK5CYII=}
; apparence des jetons (en réalité, des cases)
jeton-effects: [
noir [
gradient 1x1 127.127.127 0.0.0
oval 255.255.255
key 255.255.255
]
blanc [
gradient 1x1 255.255.255 128.128.128
oval 255.255.255
key 255.255.255
]
vide none
]
; ===Déclaration des styles de l'application
reversi-style: stylize [
; interface
button: button gold
font [colors: [0.0.0 255.0.0] shadow: none]
effect []
edge [size: 1x1 color: 0.0.0]
choice: choice gold white
font [colors: [0.0.0 255.0.0] shadow: none]
effect []
edge [size: 1x1 color: 0.0.0]
; jetons noirs et blancs
jeton: box 74x74 with [
; 'noir, 'blanc ou 'vide
data: 'vide
; coordonnées sur le plateau en cases
coords: none
; listes des cases adjacentes (pour simplifier les calculs)
gauche: droite: haut: bas: none
haut-gauche: haut-droite: bas-gauche: bas-droite: none
; déclarations dans layout
words: [
noir [
new/data: 'noir
new/effect: jeton-effects/noir
next args
]
blanc [
new/data: 'blanc
new/effect: jeton-effects/blanc
next args
]
vide [
new/data: 'vide
new/effect: jeton-effects/vide
next args
]
]
]
; clic gauche
[
; si le coup est valide
if essaie-coup face [
; case modifiée
face/data: face/parent-face/joueur
face/effect: select jeton-effects face/data
face/parent-face/joueur: select [blanc noir blanc] face/data
; affichage pour le joueur suivant
fenetre/color:
select [blanc 255.255.255 noir 0.0.0] plateau/joueur
show [fenetre face]
; pour suivre le déroulement de la partie
coups: coups + 1
; plateau plein => fin
if coups = 64 [do-face fin 'down return]
; si coup joué par la machine
if plateau/joueur = ordinateur [
; attente avant de jouer, pour voir le coup
wait 0.5
use [case][
; jouer le meilleur coup, sinon passer le tour
either case: meilleur-coup plateau/joueur [do-face case 'down][
do-face passer 'down
if not meilleur-coup plateau/joueur [do-face fin 'down]
]
]
]
]
]
; apparence du plateau de jeu (taille: 8x8 cases + bordure)
grille: box fond.png 602x602 with [
joueur: 'blanc
effect: [tile grid 75x75 0x0 34.20.14 2]
data: array/initial [8 8] 'vide
]
]
; ===Fonctions d'accès aux tableaux simulés
; primitives d'accès
x-pos: func [
"Primitive de conversion linéaire -> table."
table [any-block!] "Série"
width [integer!] "Largeur de la table"
][(-1 + index? table) // width + 1 ]
y-pos: func [
"Primitive de conversion linéaire -> table."
table [any-block!] "Série"
width [integer!] "Largeur de la table"
][1 + to-integer (-1 + index? table) / width ]
; copies à partir d'un point
gauche: func [
"Copie tous les éléments à gauche de la case."
table [any-block!] "Série"
size [pair!] "Dimensions de la table"
/local y
][
if 1 >= x-pos table size/x [return copy []]
y: y-pos table size/x
head reverse copy/part skip head table y - 1 * size/x table
]
droite: func [
"Copie tous les éléments à droite de la case."
table [any-block!] "Série"
size [pair!] "Dimensions de la table"
/local y
][
if size/x <= x-pos table size/x [return copy []]
y: y-pos table size/x
copy/part next table skip head table y * size/x
]
haut: func [
"Copie tous les éléments en haut de la case."
table [any-block!] "Série"
size [pair!] "Dimensions de la table"
/local y block b-size sk
][
if 1 >= y: y-pos table size/x [return copy []]
block: make block! b-size: y - 1
table: skip table sk: (- size/x)
loop b-size [append block table/1 table: skip table sk]
block
]
bas: func [
"Copie tous les éléments en bas de la case."
table [any-block!] "Série"
size [pair!] "Dimensions de la table"
/local y block b-size sk
][
if size/y <= y: y-pos table size/x [return copy []]
block: make block! b-size: size/y - y
table: skip table sk: size/x
loop b-size [append block table/1 table: skip table sk]
block
]
haut-gauche: func [
"Copie tous les éléments en haut à gauche de la case."
table [any-block!] "Série"
size [pair!] "Dimensions de la table"
/local x y block b-size sk
][
if 1 >= x: x-pos table size/x [return copy []]
if 1 >= y: y-pos table size/x [return copy []]
block: make block! b-size: min x - 1 y - 1
table: skip table sk: (-1 - size/x)
loop b-size [append block table/1 table: skip table sk]
block
]
haut-droite: func [
"Copie tous les éléments en haut à droite de la case."
table [any-block!] "Série"
size [pair!] "Dimensions de la table"
/local x y block b-size sk
][
if size/x <= x: x-pos table size/x [return copy []]
if 1 >= y: y-pos table size/x [return copy []]
block: make block! b-size: min size/x - x y - 1
table: skip table sk: (1 - size/x)
loop b-size [append block table/1 table: skip table sk]
block
]
bas-gauche: func [
"Copie tous les éléments en bas à gauche de la case."
table [any-block!] "Série"
size [pair!] "Dimensions de la table"
/local x y block b-size sk
][
if 1 >= x: x-pos table size/x [return copy []]
if size/y <= y: y-pos table size/x [return copy []]
block: make block! b-size: min x - 1 size/y - y
table: skip table sk: (size/x - 1)
loop b-size [append block table/1 table: skip table sk]
block
]
bas-droite: func [
"Copie tous les éléments en bas à droite de la case."
table [any-block!] "Série"
size [pair!] "Dimensions de la table"
/local x y block b-size sk
][
if size/x <= x: x-pos table size/x [return copy []]
if size/y <= y: y-pos table size/x [return copy []]
block: make block! b-size: min size/x - x size/y - y
table: skip table sk: (size/x + 1)
loop b-size [append block table/1 table: skip table sk]
block
]
; ===Initialisations de la partie
coups-depart: func [
"Cases autorisées en début de partie"
/local p
][
p: plateau/pane
p/28/effect: p/29/effect: p/36/effect: p/37/effect: [merge tint 60]
]
; Pas de coup joué
coups: 0
; Mode 2 joueurs
ordinateur: none
; ===Déclaration et initialisation de la fenêtre
fenetre: layout [
; Styles prédéfinis plus haut
styles reversi-style
; 'blanc commence
backcolor white
across
; Sélection de l'adversaire
mode: choice 178
locale mode/human-human
locale mode/computer-white
locale mode/computer-black
[
if all [
; si en mode 1 joueur...
ordinateur: select reduce [1 none 2 'blanc 3 'noir]
index? find mode/texts mode/text
; ...et tour de l'ordinateur
plateau/joueur = ordinateur
][
; Coup de la machine
use [case][
; attente avant de jouer, pour voir le coup
wait 0.5
; jouer le meilleur coup, sinon passer le tour
either case: meilleur-coup plateau/joueur [do-face case 'down][
do-face passer 'down
if not meilleur-coup plateau/joueur [do-face fin 'down]
]
]
]
]
; Sélection du niveau de difficulté en mode 1 joueur
niveau: choice locale level/min locale level/med locale level/max
; Passer le tour
passer: button locale button/skip 136 [
plateau/joueur: select [blanc noir blanc] plateau/joueur
fenetre/color:
select [blanc 255.255.255 noir 0.0.0] plateau/joueur
show fenetre
; Coup de la machine si en mode 1 joueur
if plateau/joueur = ordinateur [
use [case][
; attente avant de jouer, pour voir le coup
wait 0.5
; jouer le meilleur coup, sinon passer le tour
either case: meilleur-coup plateau/joueur [do-face case 'down][
do-face passer 'down
if not meilleur-coup plateau/joueur [do-face fin 'down]
]
]
]
]
; Terminer la partie et donner le résultat
fin: button locale button/end 136 [
use [total-blanc total-noir][
; calcul des totaux
total-blanc: total-noir: 0
foreach p plateau/pane [
if p/data = 'blanc [total-blanc: total-blanc + 1]
if p/data = 'noir [total-noir: total-noir + 1]
]
; égalité
either total-blanc = total-noir [
inform layout [
backdrop effect [gradient 1x0 255.255.255 0.0.0]
banner green locale score/draw font [shadow: 1x1] feel none
]
][
; blanc gagnant
either total-blanc > total-noir [
inform layout [
backcolor white
banner red locale score/white font [shadow: 1x1] feel none
]
][
; noir gagnant
inform layout [
backcolor black
banner locale score/black font [shadow: 1x1] feel none
]
]
]
; réinitialisation du plateau et des drapeaux
foreach p plateau/pane [p/data: 'vide p/effect: none]
coups: 0
plateau/joueur: 'blanc
ordinateur: none
mode/text: first find mode/texts locale mode/human-human
fenetre/color: white
; positions de départ
coups-depart
show [fenetre mode] show plateau/pane
]
]
; aide du jeu
aide: button "?" 20 [
inform layout [
backcolor rebolor
banner locale doc/usage-title
text as-is locale doc/usage
text locale doc/usage-close
]
]
return
; plateau de jeu
plateau: grille with [
; initialisation par des cases vides
pane: get in (layout append copy [
styles reversi-style
origin 1x1 space 1x1 across
] head insert/dup copy [] append insert/dup copy [] [jeton vide] 8 'return 8) 'pane
init: [
; déclaration des références entre les cases
use [x y p][
x: y: 1
p: pane
forall p [
p/1/coords: to-pair reduce [x y]
p/1/gauche: gauche p 8x8
p/1/droite: droite p 8x8
p/1/haut: haut p 8x8
p/1/bas: bas p 8x8
p/1/haut-gauche: haut-gauche p 8x8
p/1/haut-droite: haut-droite p 8x8
p/1/bas-gauche: bas-gauche p 8x8
p/1/bas-droite: bas-droite p 8x8
x: x + 1
if x = 9 [x: 1 y: y + 1]
]
pane: head pane
]
]
]
]
; ===Moteur logique du jeu
; validité d'un coup
essaie-coup: func [
"Vérifie si un coup est valide."
face "Case jouée"
/local f-l c ok b
][
; place occupée -> faux
if 'vide <> face/data [return false]
; coups d'introduction, seulement au centre
if coups < 4 [
use [p][
p: face/parent-face/pane
return either any [p/28 = face p/29 = face p/36 = face p/37 = face][true][false]
]
]
; cherche la présence voisine de jetons de l'adversaire suivis d'un jeton de même couleur
ok: false
c: face/parent-face/joueur
foreach f-l [gauche droite haut bas haut-gauche haut-droite bas-gauche bas-droite][
if all [face/:f-l/1 face/:f-l/1/data <> c][
b: false
foreach f face/:f-l [
if any ['vide = f/data b: c = f/data][break]
]
if b [ok: true foreach f face/:f-l [
if c = f/data [break]
f/data: c
f/effect: select jeton-effects f/data
show f
]]
]
]
ok
]
; Table de décision du joueur machine
; tactique: 1) prendre les coins du plateau
; 2) ne pas laisser l'adversaire les prendre
; 3) contrôler les bords
; 4) retourner un maximum de jetons
valeurs: [
[
36
(either ordinateur = plateau/pane/1/data [24][-18])
5.5 5.5 5.5 5.5
(either ordinateur = plateau/pane/8/data [24][-18])
36
][
(either ordinateur = plateau/pane/1/data [24][-18])
(either ordinateur = plateau/pane/1/data [2][-29])
-11 -11 -11 -11
(either ordinateur = plateau/pane/8/data [2][-29])
(either ordinateur = plateau/pane/8/data [24][-18])
][5.5 -11 1 1 1 1 -11 5.5 ][5.5 -11 1 1 1 1 -11 5.5 ][5.5 -11 1 1 1 1 -11 5.5 ][5.5 -11 1 1 1 1 -11 5.5 ][
(either ordinateur = plateau/pane/57/data [24][-18])
(either ordinateur = plateau/pane/57/data [2][-29])
-11 -11 -11 -11
(either ordinateur = plateau/pane/64/data [2][-29])
(either ordinateur = plateau/pane/64/data [24][-18])
][
36
(either ordinateur = plateau/pane/57/data [24][-18])
5.5 5.5 5.5 5.5
(either ordinateur = plateau/pane/64/data [24][-18])
36
]
]
; intérêt/risque actuel de prendre une case
valeur-case: func [
"Valeur actuelle d'une case"
offset "Position sur le plateau"
/local x y
][
x: offset/x y: offset/y
do valeurs/:y/:x
]
; Détermination du meilleur coup pour le joueur actuel, à l'aide de la table de valeurs
meilleur-coup: func [
"Recherche du meilleur coup"
joueur "Joueur en cours"
/local liste-coups p valeur b
][
; liste des coups possibles
liste-coups: copy []
; en début de partie, une des case du centre
if coups < 4 [
p: plateau/pane
foreach case random [28 29 36 37] [
if 'vide = p/:case/data [return p/:case]
]
]
; construit la liste des coups possibles accompagnés de leur pondération
foreach p plateau/pane [
if 'vide = p/data [
foreach f-l [
gauche droite haut bas
haut-gauche haut-droite bas-gauche bas-droite
][
valeur: valeur-case p/coords
if all [p/:f-l/1 p/:f-l/1/data <> joueur][
b: false
foreach f p/:f-l [
if any ['vide = f/data b: joueur = f/data][break]
valeur: valeur + valeur-case f/coords
]
if b [repend liste-coups [valeur p]]
]
]
]
]
; pas de coup possible
either empty? liste-coups [none ][
; tri avec les meilleurs coups en premier
sort/reverse/skip liste-coups 2
; suivant le niveau, on prend un des 3 meilleurs/des 2 meilleurs/le meilleur
either 6 <= length? liste-coups [
pick liste-coups 2 * random select reduce [
locale level/min 3 locale level/med 2 locale level/max 1
] first niveau/data
][second liste-coups ]
]
]
; ===Redimensionnement de la fenêtre
; référence de base
last-size: base-size: fenetre/size
; sauvegarde des dimensions et des positions de départ
base-sizes: copy []
foreach face [mode niveau passer fin aide plateau][
face: get face
repend base-sizes [face face/size face/offset]
append base-sizes either face/font [face/font/size][none]
]
; sauvegarde des coordonnées des cases
jetons-offsets: copy []
foreach jeton plateau/pane [repend jetons-offsets [jeton jeton/offset]]
; adaptation de la fenêtre à l'écran actuel
fenetre/size: fenetre/size * (system/view/screen-face/size/y / 768)
; fonction de redimensionnement, lancée la 1ère fois avant l'affichage
do resize-all: insert-event-func [
if event/type = 'resize [
use [delta-x delta-y facteur taille][
;facteur de redimensionnement
delta-x: abs fenetre/size/x - last-size/x
delta-y: abs fenetre/size/y - last-size/y
facteur: either delta-x > delta-y [
fenetre/size/x / base-size/x
][fenetre/size/y / base-size/y ]
if facteur < 0.014 [return event]
;redimensionnement des contrôles
foreach [face size offset font] base-sizes [
face/size: size * facteur
face/offset: offset * facteur
if font [face/font/size: to-integer font * facteur]
]
;redimensionnement des cases et des jetons
taille: 74x74 * facteur
foreach [jeton offset] jetons-offsets [
jeton/size: taille
jeton/offset: offset * facteur
]
;redimensionnement de la grille
taille: 75x75 * facteur
plateau/size: plateau/size / taille * taille + 2x2
change find plateau/effect pair! taille
last-size: fenetre/size
if (abs delta-x - delta-y) > 2 [
fenetre/size: base-size * facteur ]
show fenetre
]
]
event
] fenetre context [type: 'resize]
; ===Lancement du jeu
; initialisation du générateur aléatoire
random/seed now
; cases de départ
coups-depart
; affichage fenêtre principale
view/options fenetre 'resize
; ===Fin
quit