puissance4.py

Created by come-marchal

Created on January 10, 2026

6.96 KB


from ion import *
from kandinsky import *
from time import *
from random import *

#  You can put your name here
PLAYER_1 = "Joueur 1"
PLAYER_2 = "Joueur 2"
WINS_COUNTER = [0, 0]
WINNING_ROUNDS = 3
#  Color
BLUE = color(0, 0, 255)
RED = color(255, 0, 0)
YELLOW = color(255, 204, 0)
BLACK = color(0, 0, 0)
WHITE = color(255, 255, 255)
BACKGROUND_COLOR = WHITE
PLAYER_1_COLOR = RED
PLAYER_2_COLOR = YELLOW
#  Ball
BALL_RADIUS = 15
DEFAULT_BALL_COL = 3  # the middle one
# Do not touch !
BALL_COLUMNS_X = (
  25,70,115,160,205,250,295)
BALL_COLUMNS_Y = (
  210,180,150,120,90,60)
RECT_COLUMNS_X = (
  5,50,95,140,185,230,275)

def get_blank_grid(
) -> list[list]:
  return [
    [0, 0, 0, 0, 0, 0, 0],  # first row 
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],  # last and 6th row
  ]
 
def game_is_null(
  grid
) -> bool:
  last_row = grid[-1]
  for i in range(7):  # since there are 7 collumns
    if last_row[i] == 0:
      return False
  return True


def get_row(col, grid, player):
  for index_row, row in enumerate(grid):
    if row[col] == 0:
      return index_row # if there is no token yet in this row for this column
      break

def place_token_on_screen(
  row, col, grid, player, color
) -> None:
  x = BALL_COLUMNS_X[col]
  y = BALL_COLUMNS_Y[row]
  draw_ball(x, y, BALL_RADIUS, color)

def draw_grid() -> None:
  fill_rect(0, 45, 320, 180, BLACK)
  for x in RECT_COLUMNS_X:
    fill_rect(x, 45, 40, 180, BACKGROUND_COLOR)

def draw_ball(
  x_center, y_center, 
  radius, color
) -> None:
  width = height = 2*radius #  diameter of the ball
  r_sqared = radius**2
  for y in range(width):
    for x in range(height):
      dt_sqared = x**2 + y**2
      if dt_sqared <= r_sqared:
        fill_rect(x+x_center, y+y_center, 1, 1, color)
        fill_rect(x_center-x, y_center-y, 1, 1, color)
        fill_rect(x_center-x, y_center+y, 1, 1, color)
        fill_rect(x+x_center, y_center-y, 1, 1, color)


def draw_scores() -> None:
  n_wins_1 = str(WINS_COUNTER[0])
  n_wins_2 = str(WINS_COUNTER[1])
  draw_string(n_wins_1, 288, 2, PLAYER_1_COLOR)
  draw_string("/", 298, 2, BLACK)
  draw_string(n_wins_2, 308, 2, PLAYER_2_COLOR)
  
def draw_turn(
  player, color
) -> None:
  if player == 1:
    txt = PLAYER_1 + " to play"
  else:
    txt = PLAYER_2 + " to play"
  draw_string(txt, 2, 2, color)

def display_round_winner(
  player
) -> None:
  fill_rect(0, 0, 320, 45, BACKGROUND_COLOR)
  if player == 1:
    txt = PLAYER_1 + " gagne la manche !"
  elif player == 2:
    txt = PLAYER_2 + " gagne la manche !"
  elif player == 0:
    txt = "A draw. Nobody wins."
  draw_string(txt, 2, 2)

def display_game_winner(
  player
) -> None:
  fill_rect(0, 0, 320, 240, BACKGROUND_COLOR)
  if player == 1:
    txt = PLAYER_1 + " remporte la partie !"
  elif player == 2:
    txt = PLAYER_2 + " remporte la partie !"
  draw_string(txt, 20, 110)

def draw_diagonal(x1, y1, x2, y2):
  dx = x2 - x1
  dy = y2 - y1

  steps = max(abs(dx), abs(dy))

  x_inc = dx / steps
  y_inc = dy / steps

  x = x1
  y = y1

  for _ in range(int(steps) + 1):
    fill_rect(int(x)-1, int(y)-1, 2, 2, BLACK)
    x += x_inc
    y += y_inc

def display_win(
  win: tuple[tuple]
) -> None:
  (row1, col1), (row2, col2) = win
  x1 = BALL_COLUMNS_X[col1]
  x2 = BALL_COLUMNS_X[col2]
  y1 = BALL_COLUMNS_Y[row1]
  y2 = BALL_COLUMNS_Y[row2]
  if x1 == x2:
    h = y1 - y2
    fill_rect(x2, y2, 3, h, BLACK)
  elif y1 == y2:
    w = x2 - x1
    fill_rect(x1, y1, w, 3, BLACK)
  else:
    draw_diagonal(x1, y1, x2, y2)


def choose_col(
  player, color
) -> int:
  fill_rect(
    0, 0, 320, 45, 
    BACKGROUND_COLOR
    )
  draw_turn(player, color)
  draw_scores()
  col = DEFAULT_BALL_COL
  x = BALL_COLUMNS_X[col]
  draw_ball(
    x, 20, BALL_RADIUS, color
    )
  sleep(1)
  update = False
  while not keydown(KEY_OK) and not keydown(KEY_EXE):
    if keydown(KEY_LEFT):
      col -= 1
      update = True
    elif keydown(KEY_RIGHT):
      col += 1
      update = True
    if update:
      update = False
      if col > 6: col = 0
      if col < 0: col = 6
      x = BALL_COLUMNS_X[col]
      fill_rect(0, 0, 320, 45, BACKGROUND_COLOR)
      draw_turn(player, color)
      draw_scores()
      draw_ball(
        x, 20, BALL_RADIUS,
        color
        )
      sleep(0.15)
  return col

def check_win(row, col, grid):
  player = grid[row][col]
  for [u, v]   in [[1, 0], [0, 1], [1, 1], [-1, 1]]:
    total = 1
    for d in [1, -1]:
      i_col, i_row = col + d*u, row + d*v
      while (0 <= i_col < 7) and (0 <= i_row < 6):
        if grid[i_row][i_col] == player:
          total += 1
          if total == 4: return (row, col), (i_row, i_col)
          i_col += d*u
          i_row += d*v
        else: break
  return False

def get_col(gamemode, player, color):
  if player == 1 or gamemode == 1: 
    col = choose_col(player, color)
  else:
    col = ai()
  return col

def ai():
  return randint(0, 6)

def game(grid, gamemode):
  player = randint(1, 2)
  draw_grid()
  while True:
    if game_is_null(grid):
      display_round_winner(0)
      while not keydown(KEY_EXE):
        pass
      grid = get_blank_grid()
      draw_grid()
    if player == 1:
      color = PLAYER_1_COLOR
    else:
      color = PLAYER_2_COLOR
    col = get_col(gamemode, player, color)
    while grid[-1][col] != 0:  # column is full
      col = get_col(gamemode, player,)
    row = get_row(col, grid, player)
    grid[row][col] = player  # update grid
    place_token_on_screen(
      row, col, grid, player, color)  
    win = check_win(row, col, grid)
    if win:
      WINS_COUNTER[player-1] += 1
      display_round_winner(player)
      display_win(win)
      if WINS_COUNTER[player-1] == WINNING_ROUNDS:
        sleep(3)  
        break
      while not keydown(KEY_EXE):
        pass
      grid = get_blank_grid()
      draw_grid()
    player = 2 if player == 1 else 1
  display_game_winner(player)


def logo(x,y):
  # P
  fill_rect(x,y,10,50, BLACK)
  fill_rect(x+30,y,10,20, BLACK)
  fill_rect(x,y,30,10, BLACK)
  fill_rect(x,y+20,30,10, BLACK)

  # 4
  fill_rect(x+80,y,10,50, BLACK)
  fill_rect(x+50,y+20,40,10, BLACK)
  fill_rect(x+50,y+10, 10, 20, BLACK)

  draw_string("par Cosmow22", x+100, 75)


def menu():
  logo(60, 40)
  draw_string("Jouer avec un ami", 60, 120, RED)
  draw_string("Mode solo (ai)", 60, 150, BLACK)

  selected_mode = 1 # 1 vs 1 
  new_selected_mode = 1

  while not keydown(KEY_EXE) and not keydown(KEY_OK):
    if keydown(KEY_DOWN): new_selected_mode = 2
    if keydown(KEY_UP): new_selected_mode = 1

    if selected_mode != new_selected_mode:
      if new_selected_mode == 1: 
        draw_string("Jouer avec un ami", 60, 120, RED)
        draw_string("Mode solo (ai)", 60, 150, BLACK)
        selected_mode = 1
      else:
        draw_string("Jouer avec un ami", 60, 120, BLACK)
        draw_string("Mode solo (ai)", 60, 150, RED)
        selected_mode = 2
  return selected_mode

def main():
  grid = get_blank_grid()
  gamemode = menu()
  try:
    game(grid, gamemode)
  except KeyboardInterrupt:
    return

main()

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.