sautemouton.py

Created by andreanx

Created on July 11, 2020

8.08 KB

A gauche n moutons maigres en bergerie, a droite n moutons gras au pâturage. Rentre les moutons gras en bergerie et sors les moutons maigres au pâturage. Les moutons ne sautent qu’1 mouton a la fois ni reculent.

Appel : sm(n=3)

Touches : [<-][->] : choix du mouton [OK] : avancer ou sauter [clear] : quitter


from kandinsky import *
from math import *
from time import *
from ion import *

sw, sh, fw, fh, cw = 320, 222, 10, 29, 29
mouton_largeur, mouton_hauteur = 30, 22
_mouton_maigre = (25165824, 125829120, 92274688, 260048512, 264353460, 536608764, 478150654, 142606335, 4194302, 4194298, 2097018, 926488, 997494, 983158, 983158, 917556, 655412, 655412, 655460, 1179748, 131264, 131264)
_mouton_gras = (40, 6815932, 65902068, 268435454, 134217726, 1073741823, 536870861, 1073741702, 1073741696, 402652928, 469761920, 200277888, 234339072, 233486848, 468088320, 461649408, 226506240, 226505216, 213922304, 140522240, 106958848, 6303744)
_codes_touche_quitter = (6, 5, 17)
_codes_touche_gauche = (0,)
_codes_touche_droite = (3,)
_codes_touche_action = (12, 13, 4, 52)


def _print_auto_ln(s, n):
  while len(s):
    iln = s.find('\n')
    print(s[0: iln >= 0 and min(n, iln) or n])
    s = s[iln >= 0 and iln < n and iln + 1 or n:]

_print_auto_ln("A gauche n moutons maigres en bergerie, a droite n moutons gras au paturage. Rentre les moutons gras en bergerie et sors les moutons maigres au paturage. Les moutons ne sautent qu'1 mouton a la fois ni reculent.\nAppel: sm(n=3)", cw)

def sm(n=3):
  global univers
  if not isinstance(n, int) or n < 1 :
    raise ValueError("n must be a strictly positive integer")
  univers = [[1 for k in range(n)] + [0] + [-1 for k in range(n)]]
  etat_gagnant = list(univers[0])
  etat_gagnant.reverse()
  univers.extend([-1, sw // len(univers[0]), (0, 158, 0)])
  case_ancienne = -1
  touche_pressee = -1
  coups = 0
  mouton_y = _dessine_decor()
  couleur_fond = (0, 255, 255)
  while not _keydownin(_codes_touche_quitter) and univers[0] != etat_gagnant:
    rafraichissement_necessaire = False
    if _keydownin(_codes_touche_gauche + _codes_touche_droite):
      case_ancienne = univers[1]
      _change_case_courante( _keydownin(_codes_touche_gauche) and -1 or 1)
      rafraichissement_necessaire = True
    elif univers[1]>=0 and _keydownin(_codes_touche_action):
      case_ancienne = univers[1]
      if _bouge_de(1) or _bouge_de(2):
        coups += 1
        rafraichissement_necessaire = True
    if rafraichissement_necessaire:
      _dessine_moi_un_mouton(case_ancienne, univers[2], mouton_y)
      _dessine_moi_un_mouton(univers[1], univers[2], mouton_y)
      sleep(0.1)
  if univers[0] == etat_gagnant:
    print("Gagne en " + str(coups) + " coups !")
  return (univers[0] == etat_gagnant, coups)

def _keydownin(l):
  for v in l:
    if keydown(v): return True
  return False

def _bouge_de(pas):
  global univers
  case_courante = univers[1]
  case_ciblee = case_courante + univers[0][case_courante]*pas
  if case_ciblee >=0 and case_ciblee < len(univers[0]) and not univers[0][case_ciblee]:
    _echange_cases(case_courante, case_ciblee)
    univers[1] = case_ciblee
    return True
  return False

def _echange_cases(case1, case2):
  global univers
  univers[0][case2], univers[0][case1] = univers[0][case1], univers[0][case2]

def _change_case_courante(sens):
  global univers
  case_courante = univers[1]
  while not univers[0][univers[1]] or univers[1] == case_courante:
    univers[1] = (univers[1] + sens) % len(univers[0])

def _draw_horiz_line(x1, x2, y, c):
  fill_rect(x1, y, x2 - x1 + 1, 1, c)

def _draw_line(x1, y1, x2, y2, c):
  x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
  if (x2 - x1) ** 2 >= (y2 - y1) ** 2:
    if min(x1, x2) != x1: x1, y1, x2, y2 = x2, y2, x1, y1
    for k in range(x2 - x1 + 1):
      x = x1 + k
      y = int(y1 + (y2 - y1)*k/(x2 - x1))
      set_pixel(x, y, c)
  else:
    if min(y1, y2) != y1: x1, y1, x2, y2 = x2, y2, x1, y1
    for k in range(y2 - y1 + 1):
      y = y1 + k
      x = int(x1 + (x2 - x1)*k/(y2 - y1))
      set_pixel(x, y, c)

def _draw_poly_line(l, c):
  for k in range(len(l) - 1):
    _draw_line(l[k][0], l[k][1], l[k + 1][0], l[k + 1][1], c)
  return

def _fillBottomFlatTriangle(p1, p2, p3, c):
  p2, p3 = sorted([p2, p3], key=lambda x: x[0])
  invslope1 = (p2[0] - p1[0]) / (p2[1] - p1[1])
  invslope2 = (p3[0] - p1[0]) / (p3[1] - p1[1])
  curx1 = p1[0]
  curx2 = p1[0]
  for scanlineY in range(p1[1], p2[1]+1):
    _draw_horiz_line(int(curx1), int(curx2), scanlineY, c)
    curx1 += invslope1
    curx2 += invslope2

def _fillTopFlatTriangle(p1, p2, p3, c):
  p1, p2 = sorted([p1, p2], key=lambda x: x[0])
  invslope1 = (p3[0] - p1[0]) / (p3[1] - p1[1]);
  invslope2 = (p3[0] - p2[0]) / (p3[1] - p2[1]);
  curx1 = p3[0];
  curx2 = p3[0];
  for scanlineY in range(p3[1], p1[1], -1):
    _draw_horiz_line(int(curx1), int(curx2), scanlineY, c)
    curx1 -= invslope1;
    curx2 -= invslope2;

def _fill_triangle(p1, p2, p3, c):
  p1, p2, p3 = sorted([p1, p2, p3], key=lambda x: x[1])
  if p2[1] == p3[1]:
    _fillBottomFlatTriangle(p1, p2, p3, c)
  elif p1[1] == p2[1]:
    _fillTopFlatTriangle(p1, p2, p3, c)
  else:
    p4 = (int(p1[0] + ((p2[1] - p1[1]) / (p3[1] - p1[1])) * (p3[0] - p1[0])), p2[1]);
    _fillBottomFlatTriangle(p1, p2, p4, c)
    _fillTopFlatTriangle(p2, p4, p3, c)

def _fill_polygon_convex(l, c):
  for k in range(1, len(l) - 1):
    _fill_triangle(l[0], l[k], l[k + 1], c)
  return

def _draw_image_1bpp(img, x, y, c):
  for j in range(len(img)):
    v = img[j]
    i = 0
    while v:
      if v&1:
        set_pixel(x + i, y + j, c)
      v = v >> 1
      i += 1

def _dessine_moi_un_mouton(case_numero, case_largeur, y):
  global univers
  if univers[0][case_numero]:
    _draw_image_1bpp((univers[0][case_numero] > 0) and _mouton_maigre or _mouton_gras, case_numero*case_largeur + (case_largeur - mouton_largeur)//2, y, (case_numero == univers[1]) and (255, 0, 255) or (255,)*3)
  else:
    fill_rect(case_numero * case_largeur, y, case_largeur, mouton_hauteur, univers[3])

def _fillRectHorizGradientRGB(x, y, w, h, col1, col2):
  for k in range(h):
    _draw_line(x, y + k, x + w - 1, y + k, [col1[i]+(col2[i] - col1[i])*k//(h-1) for i in range(3)])

def _dessine_decor():
  global univers
  _print_auto_ln("Plantons d'abord le decor !", cw)
  d, l = int(sh // 3.125), 14
  cloture_h, m = d // 8, (sh - 2 * d) // l
  cloture_w, maison_w, porte_d = cloture_h // 4, d * 3 // 4, d // 4
  maison_h, fenetre_w = maison_w // 2, d // 8
  maison_x, maison_y, cloture_y = d*7//8, sh - 2*d - 7*d//64, sh - d - cloture_h
  couleur_fond1, couleur_fond2 = univers[3], (0, 255, 255)
  _fillRectHorizGradientRGB(0, 0, sw, sh - 2*d, couleur_fond2, (255,)*3)
  _fillRectHorizGradientRGB(0, sh - 2*d, sw, d, (0, 255, 0), couleur_fond1)
  fill_rect(0, sh - d, sw, d, couleur_fond1)
  for i in range(m):
    draw_string("*" * (i<3 and i+2 or 5), 0, l * (m - i - 1), univers[3])
  fill_rect(maison_x, maison_y, maison_w, maison_h, (255, 255, 0))
  fill_rect(maison_x + maison_w//2 - porte_d//2, maison_y + maison_h - porte_d, porte_d, porte_d, (0,)*3)
  fill_rect(0, m*l + 2, fw, sh - 5*d//4 - m*l - l, (181, 32, 0))
  for i in range(0, sw, cloture_h):
    cloture_x = i + (cloture_h - cloture_w)//2
    fill_rect(cloture_x, cloture_y, cloture_w, cloture_h, (181, 32, 0))
    if i//cloture_h % 2:
      _fill_polygon_convex(((cloture_x, cloture_y), (cloture_x - (cloture_h - cloture_w)//2, cloture_y - 3*d//64), (cloture_x, cloture_y - 7*d//64), (cloture_x + cloture_w - 1, cloture_y - 7*d//64), (cloture_x + cloture_w - 1 + (cloture_h - cloture_w)//2, cloture_y - 3*d//64), (cloture_x + cloture_w - 1, cloture_y)), (181, 32, 0))
  _fill_polygon_convex(((maison_x - 1, maison_y), (maison_x + d//4, maison_y - d//4 - 1), (maison_x + maison_w - d//4 - 1, maison_y - d//4 - 1), (maison_x + maison_w, maison_y)), (255, 0, 0))
  lst = ((sw // 2, sh - 2*d), (3 * sw // 4, sh - 2*d - d//4), (33 * sw // 40, sh - 2*d - d//8), (31 * sw // 40, sh - 2*d), (15 * sw // 16, sh - 2*d - 3*d//8), (sw, sh - 2*d - d//4), (sw, sh - 2*d))
  _fill_polygon_convex(lst[0:4], (0, 146, 255))
  _fill_polygon_convex(lst[3:7], (0, 146, 255))
  for i in range(-1, 2, 2):
    fill_rect(maison_x + maison_w//2 +i*porte_d//2 - (i<0 and fenetre_w), maison_y + d*5//64, fenetre_w, d * 3 // 32, (0, 146, 255))
  _draw_poly_line(lst, (255, 0, 255))
  mouton_y = sh - d + (d - mouton_hauteur) // 2
  for case_numero in range(len(univers[0])):
    if univers[0][case_numero]:
      _dessine_moi_un_mouton(case_numero, univers[2], mouton_y)
  return mouton_y