from random import randint
def grilleVide():
grille = []
for i in range(6):
ligne = []
for j in range(6): ligne.append('⬛')
grille.append(ligne)
return grille
def rotate(m, n):
for _ in range(n): m = list(zip(*m))[::-1]
return m
def afficher(g):
for l in range(6): print(''.join(g[l]))
def creerGrille():
grille = grilleVide()
m = [[6 * l + c for c in range(6)] for l in range(6)]
for c in range(3):
for l in range(3):
m = rotate(m, randint(0, 3))
pos = m[l][c]
x, y = pos % 6, pos // 6
grille[y][x] = '⬜'
return grille
def completeEtoiles(phrase):
return phrase + "*" * (9 - len(phrase) % 9)
def listeTrous(g):
trous = []
for l in range(6):
for c in range(6):
if g[l][c] == '⬜': trous.append(6 * l + c)
return trous
def chiffrer(phrase, grille):
phrase = completeEtoiles(phrase)
chiffre = grilleVide()
trous = listeTrous(grille)
for i, v in enumerate(phrase):
pos = i % 9
if pos == 0 and i > 0:
grille = rotate(grille, 1)
trous = listeTrous(grille)
x, y = trous[pos] % 6, trous[pos] // 6
if v == "*": v = chr(randint(65, 90))
chiffre[y][x] = v
return chiffre
def dechiffrer(crypte, grille):
clair = ''
trous = listeTrous(grille)
for i in range(36):
pos = i % 9
if pos == 0 and i > 0:
grille = rotate(grille, 1)
trous = listeTrous(grille)
x, y = trous[pos] % 6, trous[pos] // 6
clair += crypte[y][x]
return clair
grille = creerGrille()
afficher(grille)
phrase='RENDEZVOUSAQUINZEHEURESPLACELECLERC'
crypte = chiffrer(phrase, grille)
afficher(crypte)
clair = dechiffrer(crypte, grille)
print(clair)
# Substitution simple
def subSimple(phrase:str, decalage:int):
phrase = phrase.upper()
chiffrement = ''
for c in phrase:
if 'A' <= c <= 'Z':
position = (ord(c) - 65 + decalage) % 26
chiffrement += chr(65 + position)
else:
chiffrement += c
return chiffrement
# Substitution double (avec clé numérique)
def subDouble(phrase:str, decalage):
phrase = phrase.upper()
chiffrement = ''
longueur = len(decalage)
for i,c in enumerate(phrase):
if 'A' <= c <= 'Z':
position = (ord(c) - 65 + decalage[i % longueur]) % 26
chiffrement += chr(65 + position)
else:
chiffrement += c
return chiffrement
# Substitution avec mot-clé
def fabriqueAlphabet(cle:str):
lettres = list(cle.upper()) + [chr(v) for v in range(65, 91)]
alphabet = ''
for c in lettres:
if c not in alphabet: alphabet += c
tailleCle = len(set(cle))
alphabetFinal = ''
for col in range(tailleCle):
suiv = col
while suiv < 26:
alphabetFinal += alphabet[suiv]
suiv += tailleCle
return alphabetFinal
def subCleSimple(phrase:str,cle:str):
alphabet = fabriqueAlphabet(cle)
phrase = phrase.upper()
chiffrement = ''
for c in phrase:
if 'A' <= c <= 'Z':
chiffrement += alphabet[ord(c) - 65]
else:
chiffrement += c
return chiffrement
Python & Cryptographie niveau lycée : Déchiffrement des substitutions
def decryptSimple(phrase:str):
freq = [0] * 26
for c in phrase:
if 'A' <= c <= 'Z':
freq[ord(c) - 65] += 1
decal = 4 - freq.index(max(freq))
return subSimple(phrase, decal)
def decryptDouble(phrase:str, taille:int):
clair = ''
res = []
for i in range(taille):
res.append(decryptSimple(phrase[i::taille]))
return ''.join(''.join(v) for v in zip(*res))
def inverseAlphabet(chiffre:str, clair:str):
alphabetDecode = ''
for i in range(65, 91):
c = chr(i)
if c in chiffre: code = clair[chiffre.index(c)]
else: code = '?'
alphabetDecode += code
return alphabetDecode
def decryptEnPartie(phrase:str,alphabet:str):
alphabet = alphabet.upper()
phrase = phrase.upper()
chiffrement = ''
for c in phrase:
if 'A' <= c <= 'Z':
chiffrement += chr(65 + alphabet.index(c))
else:
chiffrement += c
return chiffrement
Exemples de textes :
clair = 'CHOISISSEZUNTRAVAILQUEVOUSAIMEZETVOUSNAUREZPASATRAVAILLERUNSEULJOURDEVOTREVIE'
# Clé numérique [3, 2, 1, 0]
crypte = 'FJPIVKTSHBVNWTBVDKMQXGWOXUBIPGAEWXPUVPBUUGAPDUBTUCWALNMEUWOSHWMJRWSDHXPTUGWIH'
# Extrait du livre "Le petit Prince"
princeClair = 'LESGRANDESPERSONNESMONTCONSEILLEDELAISSERDECOTELESDESSINSDESERPENTSBOASOUVERTSOUFERMESETDEMINTERESSERPLUTOTALAGEOGRAPHIEALHISTOIREAUCALCULETALAGRAMMAIRECESTAINSIQUEJAIABANDONNEALAGEDESIXANSUNEMAGNIFIQUECARRIEREDEPEINTREJAVAISETEDECOURAGEPARLINSUCCESDEMONDESSINNUMERO1ETDEMONDESSINNUMEROLESGRANDESPERSONNESNECOMPRENNENTJAMAISRIENTOUTESSEULESETCESTFATIGANTPOURLESENFANTSDETOUJOURSETTOUJOURSLEURDONNERDESEXPLICATIONSJAIDONCDUCHOISIRUNAUTREMETIERETJAIAPPRISAPILOTERDESAVIONSJAIVOLEUNPEUPARTOUTDANSLEMONDEETLAGEOGRAPHIECESTEXACTMABEAUCOUPSERVIJESAVAISRECONNAITREDUPREMIERCOUPDŒILLACHINEDELARIZONACESTTRESUTILESILONESTEGAREPENDANTLANUITJAIAINSIEUAUCOURSDEMAVIEDESTASDECONTACTSAVECDESTASDEGENSSERIEUXJAIBEAUCOUPVECUCHEZLESGRANDESPERSONNESJELESAIVUESDETRESPRESCANAPASTROPAMELIOREMONOPINIONQUANDJENRENCONTRAISUNEQUIMEPARAISSAITUNPEULUCIDEJEFAISAISLEXPERIENCESURELLEDEMONDESSINNUMERO1QUEJAITOUJOURSCONSERVEJEVOULAISSAVOIRSIELLEETAITVRAIMENTCOMPREHENSIVEMAISTOUJOURSELLEMEREPONDAITCESTUNCHAPEAUALORSJENELUIPARLAISNIDESERPENTSBOASNIDEFORETSVIERGESNIDETOILESJEMEMETTAISASAPORTEEJELUIPARLAISDEBRIDGEDEGOLFDEPOLITIQUEETDECRAVATESETLAGRANDEPERSONNEETAITBIENCONTENTEDECONNAITREUNHOMMEAUSSIRAISONNABLE'
princeChiffre = 'OGTGUCODHUQEUUPNQGTMRPUCRPTELNMEGGMALUTEUFFCRVFLHUEEVUJNVFFSHTQEQVTBRCTOXXFRWUPUIGSMHUFTGGNIQVFRHUTEURMUWQUAOCHERISASJJEDNIIVVPIUGBUFCMCXNFTDNBGUCNMDKSEFGTTDKOSLSVEMCJAECODRPOEDNBGHFFSLZBNVWOEPCHNLHJQXGDAUTJEUGEESGJNWTFJDXBIVGUEGGDOXTBGHRBROKOSXEDEVFFMRPEEVUJNQWNEUQ1EWFFMRPEEVUJNQWNEUQMEVISAQFFSSGSSRPOEVPFCROQRHPOEQVKAPCJSUKFNWQVTHUTEXNFSHVDEVVGAWKHAQVQOXTMEVGOFDPUSGGUOXLPUUUFTWQVJRWSSOGVRGQONHTEEVGYPOKDAWKPNVLBIGQOCGWDHRKTIUWOAXVSEPGUIHTFTMCJASRSIVCQIOQUEUFFSDXJOQUKALXPLHWOPHWQAUVPUWFBNVNFMRPEEHVMAJGPGUCQHLGDEVVFXDEUMDDFAXEPUSUFRYKKEVCWALUSEFQONDKURHFVPUGNIHTDOXREŒLNMAFJJNHFFLDTJZRPBCHUUTUGTUWKMEVKMOQGTTHIBRHRFNGCOTOCOULVKALCJNVKFUDWDOXTTDHOBVLGEEVVBSGGDOQVBCWUBVHEEEVVBSGGHEQUTEUKFUALBIEGBUFQVPYGDUFJFZOGTGUCODHUQEUUPNQGTJHNFSDKWUHUEEWTFSSTFSFCOASCTTUQQAPGMIRTFMRPPPLPJOQSVAQFKEQTFNFQOTUCJSXPFQXKNESCSALUTALVVNSGVLXEJDHLFFDKTALUMEARFRLGOCHUVRHNMEGGNOQFFSVKONXOFRR1RUHLBIWQVJRWSSFQOSHTWEMGWOXNBIVUBVRKSSLGMLHGUALVWRDKNEQVDOPRSEKGOSLXFMDKTTRWKOXTTEONFMHTFPRPEALVDEVVVNFJBPHCVAOQSSMGOEOWJPDTMALUOIGGTEURFNWUCODUOIGGGOUGUSYKFRJGTNLFFTRKMEVLFMHOFTWCJSDUBPRTUEHLFLXKQAUNBIVFFBUKEGHFFGRNGDHRPLLVJQXGFTGGDRDXBTHUFTOCHRDPEESGSSRPOEHVBIWDJEQEPNWGOTHFFCRPOALVSEXPIOPOFAXUTIUCJSRPOAENF'
Des propositions de simulations pour quelques calculatrices HP :
Le calcul théorique est très simple :
La réponse à trouver était donc : 5 mouvements
Version en Python
from random import random
def simul(n:int):
tot = 0 # Total de tous les mouvements
for _ in range(n): # n simulations
r = 1 # Dernier mvt de 2 vers 1
# Aller-retour de 2 vers 3 ou 4 avec probabilité 2/3
while int(3 * random()) != 0: r += 2
# On ajoute le nb de mvt au total
tot += r
# Moyenne
return tot / n
>>> simul(1000)
4.752
>>> simul(10000)
5.0992
>>> simul(100000)
4.98308
David, un collègue enseignant, a posté un tweet sur l’utilisation du mode de représentation Truth sur les anciennes calculatrices HP 48G. Voici son premier résultat, le tapis de Sierpinski :
Avec cette équation très courte :
Quelques explications : R→B permet de convertir un nombre en binaire. Pour chaque abscisse X (entre 0 et 63) et chaque Y (entre 0 et 63), on regarde s’ils ont au moins un bit en commun dans leurs écritures binaires respectives. Par exemple si X = 12 = 1100b et Y = 6 = 110b ont un bit en commun à la 3e position, on affiche dans ce cas un pixel noir à l’écran.
A partir de là j’ai trouvé la page Binary Plot du site Wollfram avec quelques visuels que j’ai voulu reproduire en Python.
Les puissances 3, 2 et 1 des entiers de 1 à 160
from kandinsky import *
for y in range(30):
n = 2 ** y
for x in range(160):
for i in range(3):
if x ** (i + 1) & n > 0:
fill_rect(2 * x, 214 - 63 * i - 4 * y, 2, 4, (0, 0, 0))
En Python il est très simple de faire des opérations bit à bit. Pour le « ET » on utilise &. Par exemple :
1100b AND 110b donne 100b = 4
Pour le « OU » le symbole est |. Par exemple 12 | 6 = 14 car 1100b | 110b = 1110b
Et le « OU EXCLUSIF » par ^. Par exemple 12 ^ 6 = 10 car 1100b ^110b = 1010b
Passons à la représentation des coefficients binomiaux :
Enfin, l’idée m’est venue de représenter la conjecture de Syracuse (on part d’un entier, s’il est pair on le divise par 2 sinon on le multiplie par 3 et on ajoute 1, la conjecture prétend que l’on arrivera à 1 au bout d’un certain temps). Avec N = 27 comme départ on arrive à 1 au bout de 111 itérations (appelé temps de vol) et le maximum atteint est 9232.
Représentons les termes de la suite sous forme binaire :
Suite de Syracuse en partant de N = 27
Il est alors assez facile de lire la valeur exacte de chacune des colonnes, par exemple du maximum. Il suffit de repérer les numéros de lignes (En bas = 0). Sur le visuel on lit les lignes 4, 10 et 13. Le nombre correspondant est donc 2^4 + 2^10 + 2^13 = 9232.
« X Y 1 + / 12 * COS Y 2 / SIN > » (En mode radians)
Version HD
sin(x * x / (y + 1) * 2) >= sin( y / (x + 1) * 10)
Version HD
sin(x / 8) % 1 > sin(y / 8) % 1
sqrt(x) % 1 >= sqrt(y) % 1
Tapis de Sierpinski
from kandinsky import *
def tapis(x, y):
while x > 0 and y > 0:
if x % 3 == 1 and y % 3 == 1: return 0
x //= 3
y //= 3
return 1
for y in range(222):
for x in range(320):
if tapis(x, y): set_pixel(x, 221 - y, (0,) * 3)
Version HD : 729 * 729 pixels (729 = 3^6)
@ Adaptation d'un script de David Cobac pour HP-48
« 3 PICK 3 MOD » 'MOD3 STO
« 3 / IP SWAP » 'IP3 STO
{ (0 0) (130 63) X 0 (0 0) TRUTH Y } 'PPAR STO
« X Y
WHILE DUP2 *
MOD3 MOD3 *
1 ≠ *
REPEAT
IP3 IP3
END
* NOT » 'EQ STO
« ERASE DRAW {} PVIEW » 'TAP STO
Lancez TAP
Version 2 :
« X Y
WHILE DUP2 DUP2
3 MOD SWAP 3 MOD
* 1 ≠ * *
REPEAT
3 / IP SWAP 3 / IP
END
* NOT »
Il y a une dizaine d’années certains internautes se sont amusés à créer des graphiques en secteurs originaux, voyons comment les reproduire en Python avec la TI-83
Le coin de ma chambre
2 murs et le sol
import ti_plotlib as plt
from ti_draw import *
from math import *
data = {-14: (143, 133, 133), 90: (158, 143, 133), 214: (93, 42, 40)}
def dec(l,n,u): return [v[n] + u for v in l]
def secteurs(data):
plt.cls()
o = (0, 0)
xy = [o]
mini = min(data.keys())
for i in range(mini, 361 + mini):
xy.append((cos(radians(i)) * 100, -sin(radians(i)) * 100))
if i in data.keys():
if i != mini: fill_poly(dec(xy, 0, 160), dec(xy, 1, 105))
set_color(*data[i])
xy = [o] + xy[-1:]
fill_poly(dec(xy, 0, 160), dec(xy, 1, 105))
secteurs(data)
show_draw()
Les données sont représentées sous la forme angle : couleur. Pour l’exemple ci-dessus, on part de l’angle -14° avec la couleur (143, 133, 133), on trace le secteur jusqu’à l’angle 90° puis on change de couleur, etc.
L’idée du programme est de tracer un polygone en partant du centre de l’écran (160, 105), la variable i parcourt les entiers allant de l’angle le plus petit (-14° dans l’exemple) jusqu’à faire un tour complet (360 – 14 = 346°). On mémorise dans la variable xy les coordonnées des points sur le bord du cercle de 1° en 1° et dès qu’il y a un changement de couleur on trace le polygone xy.
La pyramide
Même programme que précédemment mais en changeant data.
from p5 import *
from random import *
def setup():
createCanvas(600, 600)
background(20,20,20)
fill(10, 25, 10)
blendMode(SCREEN)
for x in range(30):
for n in range(1 + x):
rect(20 * x + randint(0,10), randint(-100,600), 80, 80)
def draw():
noLoop()
run()
Mode multiplier – NUMWORKS
from kandinsky import *
from random import randint
def rvb01(c): return tuple(v / 255 for v in c)
def rvb255(c): return tuple(255 * v for v in c)
def zip01(c1,c2): return zip(rvb01(c1), rvb01(c2))
def multiply(c1,c2): return rvb255(a * b for (a, b) in zip01(c1,c2))
def rect(x,y,w,h,c,mode):
for i in range(w):
for j in range(h):
rvb = mode(c, get_pixel(x + i, y + j))
set_pixel(x + i, y + j, rvb)
for x in range(0,320,8):
for y in range(0,220,3):
rect(x + randint(0, 7), y + randint(0, 6), \
randint(1, 320 - x), randint(1, 9), (250, 100, 250), multiply)
Mode différences – NUMWORKS et P5
# Version - NUMWORKS
from kandinsky import *
from random import *
def rvb01(c): return tuple(v / 255 for v in c)
def rvb255(c): return tuple(int(255 * v) for v in c)
def zip01(c1,c2): return zip(rvb01(c1),rvb01(c2))
def diff(c1,c2):
return rvb255(abs(a - b) for (a, b) in zip01(c1,c2))
def rect(x,y,w,h,c,mode):
for i in range(w):
for j in range(h):
rvb = mode(c, get_pixel(x + i, y + j))
set_pixel(x + i, y + j, rvb)
fill_rect(0,0,320,222,(250, 100, 250))
for _ in range(500):
t = randint(20,40)
rect(randint(-10, 315), randint(-10, 220), t, t, (250, 100, 250), diff)
# Version P5 - Python
from p5 import *
from random import *
c = (250, 100, 250)
def setup():
createCanvas(900, 600)
background(c)
blendMode(DIFFERENCE)
fill(c)
for _ in range(1000):
t = randint(20,80)
rect(randint(-20,900), randint(-20,600), t, t)
def draw():
noLoop()
run()
Mode addition – NUMWORKS
from kandinsky import *
from random import *
from math import cos
def rvb01(c): return tuple(v / 255 for v in c)
def rvb255(c): return tuple(int(255 * v) for v in c)
def zip01(c1,c2): return zip(rvb01(c1),rvb01(c2))
def add(c1,c2):
return rvb255(min(1,a+b) for (a, b) in zip01(c1,c2))
def rect(x,y,w,h,c,mode):
for i in range(w):
for j in range(h):
rvb = mode(c, get_pixel(x + i, y + j))
set_pixel(x + i, y + j, rvb)
fill_rect(0,0,320,222,(40,40,40))
for i in range(50):
rect(randint(-20,300), randint(-20,200), 60, 60,\
(randint(0,255), randint(0,255), randint(0,255)), add)
TISSU écossais – p5
Cet exemple a été supprimé au montage de la vidéo:
from p5 import *
def setup():
createCanvas(770, 770)
noStroke()
background((40,40,40))
blendMode(SCREEN)
fill(20, 40, 20)
for i in range(10):
for j in range(10):
rect(60 * i, 60 * j, 50 + 20 * i, 50 + 20 * j)
def draw():
noLoop()
run()
MODE addition – p5 et NUMWORKS
from p5 import *
from random import *
def setup():
createCanvas(800, 400)
noStroke()
background((50,50,50))
blendMode(ADD)
fill(20, 140, 20)
x, y = 200, 0
for i in range(100):
textSize(1 + i)
x -= 2
y += randint(-5,11)
fill(20, 140, 20)
if random()<.2: fill(255, 0, 0)
text('PROGRAMMATION', x, y)
def draw():
noLoop()
run()
from kandinsky import *
from random import *
BL, WH = (0, 0, 0), (255,) * 3
def rvb01(c): return tuple(v / 255 for v in c)
def rvb255(c): return tuple(int(255 * v) for v in c)
def zip01(c1,c2): return zip(rvb01(c1),rvb01(c2))
def screen(c1,c2):
return rvb255(1 - (1 - a) * (1 - b) for (a, b) in zip01(c1,c2))
def rect(x,y,w,h,c,mode):
for i in range(w):
for j in range(h):
rvb = mode(c, get_pixel(x + i, y + j))
set_pixel(x + i, y + j, rvb)
def dot(x, y, c, fg, t):
draw_string(c, 0, 0, fg, (0,0,0))
for v in range(18):
for u in range(9):
rect(x + u * t, y + v * t, t, t, get_pixel(u, v), screen)
def aff(txt, x, y, t):
coul = (255, 0, 0)if random()<.3 else (20, 140, 20)
for i, c in enumerate(txt):
dot(x + i * t * 9, y, c, coul, t)
fill_rect(0,0,320,222,(50,50,50))
x, y = 150, -30
for i in range(80):
x -= 2
y += randint(1,4)
aff("PROGRAMMATION", x, y, i//20)
fill_rect(0,0,20,20,(50,50,50))
Dégradés – NUMWORKS
from kandinsky import *
def rvb01(c): return tuple(v / 255 for v in c)
def rvb255(c): return tuple(int(255 * v) for v in c)
def zip01(c1,c2): return zip(rvb01(c1),rvb01(c2))
def alpha(c1, t, c2):
return rvb255(a * t + b * (1 - t) for (a, b) in zip01(c1,c2))
def rect(x,y,w,h,c,d):
(dx,dy) = d
for i in range(w):
for j in range(h):
t = 1
if dx == 1: t = 1 - i / w
elif dx == -1: t = i / w
if dy == 1: t = 1 - j / h
elif dy == -1: t = j / h
rvb = alpha(c, t, get_pixel(x + i, y + j))
set_pixel(x + i, y + j, rvb)
rect(0, 0, 200, 200, (255, 0, 0), (1,0))
rect(0, 0, 200, 200, (0, 255, 0), (0,1))
rect(0, 0, 200, 200, (0, 0, 255), (-1,0))
Effet alpha – NUMWORKS
from kandinsky import *
from random import randint, choice
coul = (255,0,255), (255,255,0), (255,127,0), (255,0,127)
def rvb01(c): return tuple(v / 255 for v in c)
def rvb255(c): return tuple(int(255 * v) for v in c)
def zip01(c1,c2): return zip(rvb01(c1),rvb01(c2))
def alpha(c1, t, c2):
return rvb255(a * t + b * (1 - t) for (a, b) in zip01(c1,c2))
def rect(x,y,w,h,c,t):
for i in range(w):
for j in range(h):
if i == 0 or j == 0 or i == w - 1 or j == h - 1:
rvb = (255,255,255)
else:
rvb = alpha(c, t, get_pixel(x + i, y + j))
set_pixel(x + i, y + j, rvb)
def effet(t):
for _ in range(150):
x, y = randint(-10,300), randint(-10,200)
w, h = randint(10,80), randint(10,80)
rect(x,y,w,h,choice(coul),t)
effet(0.15)
Le but de ces exercices est de trouver le résultat final sans taper le programme, donc en effectuant les étapes à la main sur papier comme si vous étiez l’ordinateur. Dans un second temps, des applications concrètes sont données, à vous de déterminer laquelle des fonctions mystère sera utile.
Exercice 1
def mystere(arr):
s = 0
m = arr[0]
for v in arr:
if v > m:
m = v
s += 1
return s
>> mystere([2,3,7,0,6,3])
??
>> mystere([2])
??
Exercice 2
def mystere(arr, n):
s = 0
for v in arr:
if v > n:
s += 1
return s
>> mystere([2,3,7,0,6,3], 3)
??
>> mystere([2,3,7,0,6,3], 10)
??
Exercice 3
def mystere(arr, n):
s = None
for v in arr:
if v > n:
if s is None or s > v:
s = v
return s
>> mystere([2,3,7,0,6,3], 3)
??
>> mystere([2,3,7,0,6,3], 10)
??
Exercice 4
def mystere(arr):
s = 0
for i, v in enumerate(arr):
s += v * (-1) ** i
return s
>> mystere([2,3,7,0,6,3])
??
>> mystere(range(5))
??
Exercice 5
def mystere(arr):
s = 0
for i, v in enumerate(arr):
if v == i:
s += 1
return s
>> mystere([2,1,0,3,5,4])
??
>> mystere(range(5))
??
exercice 6
def mystere(arr):
s = sorted(list(arr))
for i, v in enumerate(arr):
s[i] = arr.index(s[i])
return s
>> mystere([2,5,3,1])
??
>> mystere([2])
??
exercice 7
def mystere(arr):
for i, v in enumerate(arr):
if i > 0 and v == arr[i - 1]: return True
return False
>> mystere([2,5,3,1])
??
>> mystere([2,5,5,3])
??
>> mystere(range(10))
??
Exercice 8
def mystere(arr1, arr2):
s = []
for v in arr1:
if v in arr2 and v not in s:
s.append(v)
return s
>> mystere([2,5,5,3], [4,4,2,5,7])
??
>> mystere([2],[4])
??
Exercice 9
def mystere(arr1, arr2):
s = []
for v in arr1 + arr2:
if v not in s:
s.append(v)
return s
>> mystere([2,2,2,7],[4,4,5])
??
Pour aller plus loin : Ecrire une fonction analogue (l’ordre des éléments pouvant être différent), en utilisant set, union et list.
exercice 10
def mystere(arr):
s = []
for u in arr:
n = 0
for v in arr:
if v > u:
n += 1
s.append(n)
return s
>> mystere([8,2,5,1,7])
??
>> mystere([1])
??
>> mystere(range(5))
??
Applications concrètes
Pour chacun des exemples concrets ci-dessous, retrouvez quelle fonction mystère serait adaptée pour répondre à la question.
Société de transport « Okilo »
La société OKILO a plusieurs camions, chacun étant spécialisé dans le transport de colis de plus de X kilos. Par exemple le camion ci-dessous ne transporte que des colis de plus de 10 kilos, il va donc refuser 3 colis sur les 5 et ne garder que les 2 de 15 et 13 kg.
Ce camion n’accepte que les colis de plus de 10 kilos
Quelle fonction mystere permet, à partir d’une liste de poids et de la valeur minimale acceptée par le camion, d’obtenir le nombre de colis qui seront transportés ?
Mélange
Vous mettez 6 billes numérotées de 0 à 5 dans un sac. Au hasard vous les sortez une à une et les placez dans des boites numérotées également de 0 à 5. On se demande combien de billes ont un numéro correspondant à celui de leur boite ?
Seules les billes n°2 et 5 sont bien rangées, c’est-à-dire dans des boites correspondant à leurs numéros
Quelle fonction mystere permet, à partir d’une liste de numéros ([1, 0, 2, 4, 3, 5] pour l’exemple) de connaitre le nombre de billes qui sont bien rangées (2 pour l’exemple) ?
Nombre de personnes dans le bus
Des personnes montent et descendent d’un bus. Par exemple la liste [3,2,8,0,6,3] signifie qu’au premier arrêt 3 personnes sont montées et 2 sont descendues. A l’arrêt suivant 8 personnes montent et aucune ne descend et enfin au 3e arrêt, 6 montent et 3 descendent. Sachant qu’il y avait 10 personnes dans le bus avant d’arriver au 1er arrêt, combien restera-t-il de personnes dans le bus après le 3e arrêt ?
Combien y aura-t-il de personnes dans le bus après le 3e arrêt ?
Quelle fonction mystere vous aidera à trouver le nombre final de passagers ?
Combien sont plus grands que moi ?
5 personnes montrent aux autres leurs tailles respectives sur un petit panneau. Ainsi, tout le monde voit les tailles de tout le monde. Chacun se demande « Combien sont plus grands que moi ? »
Chacun se demande combien d’individus dans le groupe sont plus grands qu’eux
La plus grande personne pensera donc à zéro et la plus petite à 4.
Quelle fonction mystere permet, à partir de la liste des tailles [1.6, 1.95, 1.56, 1.61, 1.52] d’obtenir la liste des nombres auxquels chacun pense ?
Ecrivains célèbres
On se demande s’il existe des écrivains dont le nom et le prénom s’écrivent avec des lettres différentes. Par exemple pour VICTOR HUGO, on voit qu’il y a la lettre O en commun, cet auteur ne correspond pas à ce que l’on recherche.
Quelle fonction mystere permet, à partir de 2 chaines de caractères (une pour le prénom, l’autre pour le nom) de nous dire quelles lettres sont communes ?
Le ‘O’ est commun à ‘VICTOR’ et ‘HUGO’
Arriverez-vous à trouver un auteur vérifiant ce que l’on cherche ?
secret défense
Voici la technique de cryptographie que vous voulez employer : – La phrase à transmettre est MESSAGEIMPORTANT – Comme il y a 16 lettres dans ce message, vous prenez les 16 premières lettres de l’alphabet que vous mélangez au hasard. Par exemple en tapant :
– Maintenant vous regardez les rangs des lettres en partant de ‘A’ jusqu’à ‘P’ dans cet alphabet mélangé. Le ‘A’ est à la 6e position, le ‘B’ la position 3, le ‘C’ à la position 1 etc. – On obtient la liste : [6, 3, 1, 11, 13, 9, 2, 0, 5, 12, 14, 8, 7, 4, 10, 15] – Finalement, pour crypter votre message, vous allez prendre sa lettre n°6 (le E) puis la n°3 (le S), puis la n°1 (le E) etc. jusqu’à la 16e position. – Vous obtenez le mot codé : ESERAPSMGTNMIAOT
Quelle fonction mystere permettra de faire fonctionner le programme ci-dessous ?
def coder(txt,cle):
ordre = mystere(cle)
s = ""
for i in range(len(txt)):
s += txt[ordre[i]]
return s
>> coder("MESSAGEIMPORTANT", "HCGBNIAMLFODJEKP")
ESERAPSMGTNMIAOT
Gratte-ciels
Des immeubles de différentes hauteurs sont côte à côte. On se demande combien vont être touchés par des rayons de lumières parallèles au sol et provenant de la gauche. Sur le visuel ci-dessous les hauteurs sont [2, 2, 3, 2, 6, 3, 6, 2] et l’on voit que seuls 3 seront touchés par les rayons (les autres sont cachés par au moins un plus grand à leur gauche).
Seuls 3 immeubles seront touchés
Quelle fonction mystere va vous aider à compter le nombre d’immeubles touchés par les rayons ?
parterre de fleurs
Afin d’obtenir le label « Villes et villages fleuris », le maire décide de créer des parterres de fleurs en alternant fleurs et tulipes. Voici un exemple qui lui convient : 🌼🌷🌼🌷🌼🌷🌼🌷
Par contre celui-ci ne convient pas : 🌼🌷🌼🌷🌷🌼🌷🌼🌷 puisque 2 tulipes sont côte à côte.
Quelle fonction mystere va vous permettre de savoir si un parterre est correct ou non ?
Suite à ma vidéo d’initiation à JavaScript concernant la recherche de mots (palindromes, anacycliques, mots croissants…), je vous propose ici les traductions en Python
Importer les dictionnaires
Enregistrez le fichierdicos.py dans un dossier et créez un fichier recherche.py dans ce même dossier avec pour contenu :
import dicos
print(len(dicos.dico5))
En exécutant le fichier vous devriez voir le nombre 7276 qui correspond au nombre de mots de 5 lettres.
Mots en sens inverse et palindromes
import dicos
def inverse(mot):
return mot[::-1]
def palindrome(dico):
return [mot for mot in dico if mot == inverse(mot)]
Par exemple tourner la face du haut (U = Up) revient à mettre la vignette 8 en 9, la vignette 9 en 11, la vignette 11 en 10 et la vignette 10 en 8, ce qui est est noté (8,9,11,10). Mais cela bougera également les vignettes (4,0,17,13) et (5,1,16,12). Le principe est le même pour les mouvements R (Right), L (Left), D (Down) et P (Arrière).
Remplissage des faces :
H = ((1,0,0),(0,0,-1),(-1,0,0))
FACES = ((0,0,0),H),((0,0,-1.1),H),((0,-1.1,0),H),((0,-1.1,-1.1),H)
Etapes pour dessiner la vignette n°8
Exemple avec la vignette n°8 : On part du point de coordonnées (0,0,0) puis on ajoute successivement les vecteurs qu’il y a dans H, on obtient (1,0,0) puis (1,0,-1) et (0,0,-1). Nous avons les 4 coins de la vignette.
Les fonctions face, pos2D et remplir permettent alors de remplir cette surface avec la couleur voulue (pos2D transforme les coordonnées 3D en coordonnées à l’écran)
Le ,2 que l’on voit sur les 2 lignes ci-dessous permet de remplir plus rapidement la zone. Essayez avec ,3 et ,1 pour voir la différence.
for col in range( ... ,2):
for lig in range( ... ,2):
La fonction permu transforme la position du cube (liste de 24 nombres) en une nouvelle liste suivant le choix du mouvement. La nouvelle position est mise dans la variable suiv, ce qui permet lors de la mise à jour de l’affichage de ne remplir que les vignettes qui ont changé de couleur :
def aff(suiv,pos,force=0):
for n, c in enumerate(suiv):
if pos[n] != c: face(n,RVB[c]) # Changement de couleur ?
Rotation du cube entier :
Pour faire tourner le cube avec les 4 flèches, on applique plusieurs mouvements, par exemple avec la flèche du haut on applique les 4 mouvements 1,2,2,2. Répéter 3 fois le mouvement n°2 revient à appliquer 2 à l’envers (ce que l’on note souvent avec ‘, par exemple R’)
Cube terminé ?
L’idée est de parcourir les vignettes n°0, 1… 23 et de compter combien de fois on a changé de couleurs. Si ce nombre correspond à 6, le cube est terminé :
def fin(pos):
c, nb = pos[0], 1
for v in pos:
if v != c:
c = v
nb += 1
return nb != 6
Programme principal :
while True:
fill_rect(0,0,320,222,(0,)*3) # Fond noir
pos, jouer = melange(), True # mélange du cube
while jouer:
suiv = choix(key(TOUCHES), pos) # Future position du cube
aff(suiv,pos) # Affichage de la position
pos = list(suiv) # C'est la nouvelle position
sleep(.2)
jouer = fin(pos) # Le cube est-il fini ?
import turtle
t = turtle.Turtle()
t.speed(0) ; t.hideturtle()
# Ecran avec fond noir
t.color(0,0,0)
t.begin_fill()
for (x,y) in ((-200,200),(200,200),(200,-200),(-200,-200),(-200,200)):
t.goto(x,y)
t.end_fill()
# Représentation des clous
def clou(A):
t.pensize(5) ; t.color((160,140,130))
t.penup(); t.goto(A); t.pendown(); t.goto(A)
# Fil entre le point "A" et le point "B" avec la couleur "c"
# et ajout des clous aux extrémités
def fil(A,B,c):
clou(A) ; t.pensize(1) ; t.pencolor(c) ;
t.goto(B) ; clou(B)
# Division en "n" points du segment entre "a" et "b"
def segment(a,b,n):
return [[(i*PTS[b][0]+(n-1-i)*PTS[a][0])/(n-1), \
(i*PTS[b][1]+(n-1-i)*PTS[a][1])/(n-1)] for i in range(n)]
# Remplissage en utilisant 2 segments S1 et S2
# Chaque point de S1 va vers un point de S2
# puis on revient de S2 vers S1
# sauf si c'est le dernier point
def remplir(S1, S2, c):
for i in range(len(S1)):
fil(S1[i], S2[i], c)
if i < len(S1) - 1 : fil(S2[i], S1[i+1], c)
# Les coordonnées ont été trouvées en utilisant Geogebra
# et l'image fournie en exemple sur le site
PTS = (-142,-100),(0,-110),(2,196),(-62,-122),(142,-116),(-136,-124),
(-122,-152),(142,-124),(126,-164),(-156,-186),(166,-196)
# segment(0,1,40) correspond au segment de (-142,-100) à (0,-110)
# avec 40 divisions
remplir(segment(0,1,40), segment(2,1,40), (180,40,30))
remplir(segment(3,4,40), segment(4,2,40), (240,30,50))
remplir(segment(5,6,20), segment(7,8,20), (120,150,160))
remplir(segment(6,9,10), segment(8,10,10), (0,100,240))
import turtle
from math import *
t = turtle.Turtle()
t.speed(0) ; t.hideturtle()
t.color(0,0,0)
t.begin_fill()
for (x,y) in ((-200,200),(200,200),(200,-200),(-200,-200),(-200,200)):
t.goto(x,y)
t.end_fill()
def clou(A):
t.pensize(5) ; t.color((160,140,130))
t.penup(); t.goto(A); t.pendown(); t.goto(A)
def fil(A,B,c):
clou(A) ; t.pensize(1) ; t.pencolor(c) ;
t.goto(B) ; clou(B)
# Cercle rayon R divisé en N points
# Position du n-ième clou
def Ce(R,N,n,D=1,d=0):
return [R*sin(2*pi*(n+d/D)/N), R*cos(2*pi*(n+d/D)/N)]
# Partie bleue
c = (175,220,240)
for i in range(14):
fil(Ce(180,80,-14+2*i),Ce(180,80,-13+2*i),c)
fil(Ce(180,80,-13+2*i),Ce(180,80,14+4*i),c)
if i != 13:
fil(Ce(180,80,14+4*i),Ce(180,80,15+4*i),c)
fil(Ce(180,80,15+4*i),Ce(180,80,16+4*i),c)
fil(Ce(180,80,16+4*i),Ce(180,80,-12+2*i),c)
# Partie rose
c = (250,160,150)
pts1 = (40,2),(54,2),(68,4),(14,2),(28,2)
pts2 = (28,2),(29,2),(15,2),(70,4),(55,2),(41,2),(42,2)
for i in range(7):
for j,(a,b) in enumerate(pts1[:-1]):
fil(Ce(180,80,a+b*i),Ce(180,80,pts1[j+1][0]+pts1[j+1][1]*i),c)
if i != 6:
for k,(u,v) in enumerate(pts2[:-1]):
fil(Ce(180,80,u+v*i),Ce(180,80,pts2[k+1][0]+pts2[k+1][1]*i),c)
import turtle
from math import *
t = turtle.Turtle()
t.speed(0) ; t.hideturtle()
t.color(0,0,0)
t.begin_fill()
for (x,y) in ((-200,200),(200,200),(200,-200),(-200,-200),(-200,200)):
t.goto(x,y)
t.end_fill()
def clou(A):
t.pensize(5) ; t.color((160,140,130))
t.penup(); t.goto(A); t.pendown(); t.goto(A)
def fil(A,B,c):
clou(A) ; t.pensize(1) ; t.pencolor(c) ;
t.goto(B) ; clou(B)
def Ce(R,N,n,D=1,d=0):
return [R*sin(2*pi*(n+d/D)/N), R*cos(2*pi*(n+d/D)/N)]
for (a,b,c) in ((14,63,(120,110,180)),(64,33,(240,90,40))):
for i in range(50):
for n in range(2): fil(Ce(180,80,a+i),Ce(180,80,b+i+n),c)
import turtle
t = turtle.Turtle()
t.speed(0) ; t.hideturtle()
t.color(115,80,45)
t.begin_fill()
t.goto(0,-400); t.circle(800) # fond marron
t.end_fill()
col, lig, r = 9, 9, 20 # 9*9 motifs de rayon 20
h,e = 4.3*r, .75*r # Calculs des espacements
def motif(x,y,a,r):
t.penup(); t.goto(x,y)
t.setheading(a) # Orientation pour obtenir une des 4 figures
# on parcourt les 4 couleurs
for c in ((240,210,7),(230,130,5),(190,90,14),(110,60,30)):
t.color(c)
t.begin_fill()
t.circle(r,steps=60) # 60 pour un tracé plus précis
r /= 1.45 # Tailles de cercles : jaune, orange, marron...
t.end_fill()
for c in range(col):
for l in range(lig):
a = 45+90*(0,1,3,2)[l%2+2*(c%2)] # angle départ
# Motif à la bonne place et avec la bonne orientation
motif(-160+h*(c//2)+e*(c%2),160-e*(l%2)-h*(l//2),a,r)
Répétition de cercles
Distance entre 2 centres
import turtle
from random import *
from math import sqrt
t = turtle.Turtle()
t.speed(0) ; t.hideturtle()
t.pensize(1)
t.color((220,210,130))
r = 20 # taille des cercles
d = sqrt(3) / 2
nc, nl = 400 // r, 280 // r
for c in range(nc):
for l in range(nl):
t.penup()
t.goto(-160 + c * r * d, -140 + l * r - (c % 2) * r / 2)
t.pendown()
t.circle(r)
import turtle
from math import sqrt
t = turtle.Turtle()
t.speed(0) ; t.hideturtle()
h = 20 # taille du motif
p, d = h // 2, sqrt(3) / 2
nb = 1 + int(800 / 3 / h / d)
def face(x,y):
t.penup(); t.goto(x,y); t.pendown()
t.setheading(30)
# Chacune des 3 faces a une couleur
for c in ((60,)*3,(230,200,0),(230,165,20)):
t.color(c)
t.begin_fill()
# Dessin d'une face et remplissage
for (u,v) in ((h,120),(p,60),(p,300),(p,60),(p,120),(h,-60)):
t.forward(u)
t.right(v)
t.end_fill()
# On place les motifs
for c in range(nb):
for l in range(nb):
face(-200 + (h + p) * d * c, \
-200 + l * (h + p) - (c % 2) * (h + p) / 2)
from kandinsky import *
from math import sqrt
from random import randint
# nb d'anneaux (couleurs alternées) et largeur anneau
(nb, r) = (randint(3,40), randint(2,10))
p = nb * r
COUL = (70, 75, 75)
fill_rect(0, 0, 320, 222, (255, 210, 0))
def cercles(u,v,du,dv):
# Bord opposé (en diagonale) au point de départ (u,v)
(u2, v2) = (u + du * nb * r, v + dv * nb * r)
# Pour chaque pixel du carré p * p
for x in range(p):
for y in range(p):
# Recherche du n° de l'anneau
d = int(sqrt(x ** 2 + y ** 2) / r)
# Si c'est un nb impair et qu'il est inférieur au nb d'anneaux total
if d & 1 and d < nb:
# On le dessine (gris foncé)
set_pixel(u + du * x, v + dv * y, COUL)
# Distance point par rapport à l'autre extrémité
# et calcul du n° de l'anneau
d2 = int(sqrt((x - p) ** 2 + (y - p) ** 2) / r)
# On dessine pixel si en dehors des anneaux précédents
if d2 > nb - 2:
set_pixel(u2 - du * x, v2 - dv * y, COUL)
def motif(x,y):
# (a,b) = position départ du motif et (c,d) = directions du remplissage en x et y
# Faire varier (c,d) avec d'autres combinaisons de 1 et -1
for (a,b,c,d) in ((1,1,-1,-1),(2,0,-1,1),(0,2,1,-1),(1,1,1,1)):
cercles(x + a * p, y + b * p, c, d)
for c in range(1+ 160 // p):
for l in range(1 + 110 // p): motif(2 * c * p,2 * l * p)