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("passé",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("Terminé ! 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()