# reversi.py

Created by cent20

Created on May 05, 2023

8.42 KB

### 𝗥𝗲𝘃𝗲𝗿𝘀𝗶

Python Game 🎮 v1.01 for Numworks, all models.

By Thomas S. & Vincent ROBERT avril 2023.

Un projet libre réalisé dans la cadre de l'enseignement de spécialité NSI.

Learn more about reversi on: nsi.xyz/puissance4 (FR)

#### Changelog

Convert v1.2.1 - 28/04/2023:
- Initial version

```from random import choice
from kandinsky import fill_rect as rec, draw_string as txt
from ion import keydown as k
from time import sleep

# Reversi 1.2.1 NumWorks, 27.04.2023
# Par Thomas S. & Vincent ROBERT
# https://nsi.xyz/reversi

ai_lvl_list = ("Facile","Normal")
mode_de_jeu = ("J-2","IA")
directions = ([0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1])
col = ((100,203,111),(220,)*3,(60,)*3,(148,113,222),(242,0,0),(255,183,52),(255,)*3,(60,139,72),(90,)*3,(180,)*3,(160,)*3,(242,)*3)
len_x,len_y,c = 8,8,20
x_g = (320 - (1+len_x*(c+2))) // 2
y_g = (200 - (1+len_y*(c+2))) // 2

def grille(x, y, t_x, t_y, c, col):
for w in range(t_x):
for h in range(t_y):
rec(1+x+w*(c+2), 1+y+h*(c+2), c, c, col)

def cercle(x,y,col,s=0):
for d in range(6):
rec(x-d+(d==0)+2*s, y+d+(d==5)+2*s, 6+2*d-2*(d==0)-4*s, 16-2*d-2*(d==5)-4*s, col)

def getCase(g_in, x, y, col_mode=False):
if col_mode:
if 0 <= g_in[y][x] <= 2:
return col[g_in[y][x]]
return None
return -1 if x < 0 or x >= len_x or y < 0 or y >= len_y else g_in[y][x]

def setCase(g_in_in, x, y, value):
g_in_in[y][x] = value

def wait(buttons=(0,1,2,3,4,5,52)):
while True:
for i in buttons:
if k(i):
while k(i): True
return i

def deplacement(pos_old=[], for_error=False):
global c
if not(for_error):
if pos_old != []:
x, y = pos_old
if getCase(g,x,y) in (1,2):
rec(x_g+1+x*(c+2),y_g+1+y*(c+2),c,c,col[0])
cercle(x_g+8+(c+2)*x,y_g+3+(c+2)*y,getCase(g,x,y,True))
else:
rec(x_g+1+x*(c+2),y_g+1+y*(c+2),c,c,getCase(g,x,y,True))
x, y = pos
rec(x_g+1+x*(c+2),y_g+1+y*(c+2),c,c,col[7])
cercle(x_g+8+(c+2)*x,y_g+3+(c+2)*y,col[1] if player_turn == 1 else col[2],1)
case = getCase(g,x,y)
if case != 0:
cercle(x_g+8+(c+2)*x,y_g+3+(c+2)*y,getCase(g,x,y,True))
else:
rec(x_g + 1 + pos[0]*(c+2),y_g + 1 + pos[1]*(c+2), c, c, col[4])
sleep(0.1542)
affichage()

def update():
global c
for y in range(len_y):
for x in range(len_x):
if getCase(g,x,y) in (1,2):
rec(x_g+1+x*(c+2), y_g+1+y*(c+2), c, c, col[0])
cercle(x_g+8+(c+2)*x, y_g+3+(c+2)*y, getCase(g, x, y, True))
else:
rec(x_g+1+x*(c+2), y_g+1+y*(c+2), c, c, getCase(g, x, y, True))
deplacement()

def affichage():
if param == 1:
txt("<", 283-len(mode_de_jeu[ai_enable_indice])*5-15, y_g+2, col[10])
txt(">",283+len(mode_de_jeu[ai_enable_indice])*5+5, y_g+2, col[10])
elif param == 2:
txt("<", 283-15, y_g+(c+2)*7+17, col[10])
txt(">",283+5,y_g+(c+2)*7+17,col[10])
txt("J-1",20,y_g+2,col[8])
cercle(32,y_g+c+2+3,col[2])
txt("Score",10,y_g+(c+2)*3+2,col[8])
rec(25,y_g+(c+2)*4+2,22,18,col[6])
txt(str(sc_noir),35-len(str(sc_noir))*5,y_g+(c+2)*4+2,col[9])
if not(no_round in (0,2)):
rec(9,y_g+(c+2)*6+1,52,(c+2)*2, col[3])
txt("Tour",15,y_g+(c+2)*6+2, col[11], col[3])
txt("passé",10,y_g+(c+2)*7+2, col[11], col[3])
sleep(0.242)
else:
rec(9,y_g+(c+2)*6+1, 52, (c+2)*2, col[6])
txt(mode_de_jeu[ai_enable_indice],283-len(mode_de_jeu[ai_enable_indice])*5,y_g+2,col[8])
cercle(280,y_g+c+2+3,col[1])
txt("Score",258,y_g+(c+2)*3+2,col[8])
rec(273,y_g+(c+2)*4+2,22,18,col[6])
txt(str(sc_blanc),283-len(str(sc_blanc))*5,y_g+(c+2)*4+2,col[9])
if sets["ai_enable"]:
txt("Niveau",253,y_g+(c+2)*6+2,col[8])
txt(ai_lvl_list[ai_lvl_indice],283-len(ai_lvl_list[ai_lvl_indice])*5,y_g+(c+2)*7+2,col[9])
if sc_noir == 42:
txt("<3",25,y_g+(c+2)*5+2,(255,0,0))
else:
rec(25,y_g+(c+2)*5+2,20,18,col[6])
if sc_blanc == 42:
txt("<3",273,y_g+(c+2)*5+2,(255,0,0))
else:
rec(273,y_g+(c+2)*5+2,20,18,col[6])

def do_pion(mode, pion_x, pion_y, directions_in, ai_ask=False):
if getCase(g,pion_x, pion_y) != 0:
return False
result = []
if ai_ask:
dist_totale = []
global sc_noir,sc_blanc
pion_adverse = 1 if player_turn == 2 else 2
for d in directions_in:
x,y,dir_x,dir_y = pion_x,pion_y,d[0],d[1]
current = getCase(g, x + dir_x, y + dir_y)
dist_parcourue = 1
while pion_adverse == current:
x,y = x+dir_x,y+dir_y
if mode == 1:
sc_blanc += 1-2*(player_turn!=1)
sc_noir += 1-2*(player_turn!=2)
setCase(g, x, y, player_turn)
current = getCase(g, x + dir_x, y + dir_y)
dist_parcourue += 1
if mode == 0 and dist_parcourue > 1 and current == player_turn:
if not(ai_ask):
result.append(d)
else:
dist_totale.append(dist_parcourue)
result.append(d)
else:
continue
if mode == 1:
if player_turn == 1:
sc_blanc += 1
else:
sc_noir += 1
setCase(g,pion_x,pion_y,player_turn)
else:
if ai_ask:
result.append(sum(dist_totale))
return result

def has_legal_hit():
legal_hits = []
for y in range(len_y):
for x in range(len_x):
if do_pion(0,x,y,directions):
legal_hits.append([x,y])
return legal_hits

def ai(lvl):
if lvl == 0:
return choice(has_legal_hit())
elif lvl == 1:
legal_hits = has_legal_hit()
temp = []
plus_grand = [[],0]
for i in range(len(legal_hits)):
legal_hits[i] = [legal_hits[i],do_pion(0,legal_hits[i][0],legal_hits[i][1],directions,True)]
for i in legal_hits:
if i[1][-1] > plus_grand[1]:
plus_grand = [[i[0]],i[1][-1]]
elif i[1][-1] == plus_grand[1]:
plus_grand[0].append(i[0])
return choice(plus_grand[0])

def action(position):
global player_turn
result = do_pion(0,position[0],position[1],directions)
if result != [] and result != False:
do_pion(1,position[0],position[1],result)
player_turn = 1 if player_turn == 2 else 2
update()
else:
deplacement(for_error=True)

def gameover():
rec(0,200,320,22,col[5])
txt("Terminé ! Relancer avec OK",30,202,col[11],col[5])
while 1:
key_pressed = wait()
if key_pressed in (4,52):
break
init()

def init():
global sets,g,player_turn,sc_noir,sc_blanc,no_round,pos,ai_enable_indice,ai_lvl_indice,param
sets = {"player_choice": 2,"ai_enable": False, "ai_lvl": 0}
g = [[0 for i in range(len_x)] for i in range(len_y)]
g[3][3],g[3][4],g[4][3],g[4][4] = 1,2,2,1
player_turn,sc_noir,sc_blanc,no_round = 2,0,0,0
pos = [2,3]
rec(0,0,320,200,col[6])
rec(0,200,320,22,col[3])
txt("Code by nsi.xyz/reversi",45,202,col[11],col[3])
grille(x_g,y_g,len_x,len_y,c,col[0])
param = 1
ai_enable_indice = 1
ai_lvl_indice = 0
affichage()
while 1:
key_pressed = None
key_pressed = wait()
if key_pressed == 0:
if param == 1:
ai_enable_indice = (ai_enable_indice-1) % 2
elif param == 2:
ai_lvl_indice = (ai_lvl_indice-1) % 2
elif key_pressed == 3:
if param == 1:
ai_enable_indice = (ai_enable_indice+1) % 2
elif param == 2:
ai_lvl_indice = (ai_lvl_indice+1) % 2
if key_pressed in (4,52):
if param == 1:
if ai_enable_indice == 1:
sets["ai_enable"] = True
param += 1
else:
sets["ai_enable"] = False
param = 0
rec(248,y_g+2,71,18,col[6])
break
else:
if sets["ai_enable"]:
sets["ai_lvl"] = 0 if ai_lvl_indice == 0 else 1
param = 0
rec(248,y_g+(c+2)*7+17,71,18,col[6])
break
if key_pressed == 5 and param == 2:
param -= 1
sets["ai_enable"] = False
rec(248,y_g+(c+2)*6+2,71,55,col[6])
if key_pressed != None:
rec(248,y_g+2,71,18,col[6])
rec(248,y_g+(c+2)*7+2,71,18,col[6])
affichage()
play()

def play():
global player_turn,sc_noir,sc_blanc,no_round
sc_noir,sc_blanc = 2,2
update()
while 1:
key_pressed = None
pos_old = list(pos)
if has_legal_hit() == []:
player_turn = 1 if player_turn == 2 else 2
no_round += 1
if no_round == 2:
affichage()
break
affichage()
continue
else:
no_round = 0
if sets["ai_enable"] and player_turn != sets["player_choice"]:
sleep(0.242)
pos_ai = ai(sets["ai_lvl"])
action(pos_ai)
continue
key_pressed = wait()
if key_pressed == 1:
pos[1] = (pos[1]-1) % 8
elif key_pressed == 2:
pos[1] = (pos[1]+1) % 8
elif key_pressed == 3:
pos[0] = (pos[0]+1) % 8
elif key_pressed == 0:
pos[0] = (pos[0]-1) % 8
elif key_pressed in (4,52):
if sets["ai_enable"] and player_turn == sets["player_choice"]:
action(pos)
elif not(sets["ai_enable"]):
action(pos)
if key_pressed != None:
deplacement(pos_old)
gameover()
init()```