Page 1 sur 3 • 1, 2, 3
- Flo44Érudit
Bonjour,
Je cherche un génénateur ou une méthode rapide et efficace pour générer ce type de pyramide :
http://pegame.ens-lyon.fr/activite.php?rubrique=2&id_theme=28&id_activite=81&
En effet, je veux en faire avec des relatifs, et les toutes faites que je trouve ne correspondent pas du tout à l'approche que j'ai eue avec mes élèves, ou bien sont avec des nombres non entiers (et je sais que c'est trop difficile pour la majorité de mes élèves).
Merci.
Je cherche un génénateur ou une méthode rapide et efficace pour générer ce type de pyramide :
http://pegame.ens-lyon.fr/activite.php?rubrique=2&id_theme=28&id_activite=81&
En effet, je veux en faire avec des relatifs, et les toutes faites que je trouve ne correspondent pas du tout à l'approche que j'ai eue avec mes élèves, ou bien sont avec des nombres non entiers (et je sais que c'est trop difficile pour la majorité de mes élèves).
Merci.
- Pourquoi 3,14159Érudit
Avec un tableur tu peux réaliser cela en fusionnant les cellules deux à deux et en les décalant de ligne en ligne. Puis tu sélectionnes ta pyramide pour la coller dans ton document.
_________________
"Placez votre main sur un poêle une minute et ça vous semble durer une heure. Asseyez vous auprès d'une jolie fille une heure et ça vous semble durer une minute. C'est ça la relativité. " (Albert Einstein).
- ben2510Expert spécialisé
Si tu aimes le LaTeX et le Python,
voila une solution avec TikZ.
&textReferences=false]générer le TikZ en Python
voila une solution avec TikZ.
&textReferences=false]générer le TikZ en Python
- Code:
\documentclass[10pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}
\begin{document}
\begin{tikzpicture}
\draw (4,5)--(6,5)--(6,4)--(4,4)--cycle;
\draw (5,4.5) node{$14$};
\draw (3,4)--(5,4)--(5,3)--(3,3)--cycle;
\draw (4,3.5) node{$23$};
\draw (5,4)--(7,4)--(7,3)--(5,3)--cycle;
\draw (6,3.5) node{$25$};
\draw (2,3)--(4,3)--(4,2)--(2,2)--cycle;
\draw (3,2.5) node{$32$};
\draw (4,3)--(6,3)--(6,2)--(4,2)--cycle;
\draw (5,2.5) node{$34$};
\draw (6,3)--(8,3)--(8,2)--(6,2)--cycle;
\draw (7,2.5) node{$36$};
\draw (1,2)--(3,2)--(3,1)--(1,1)--cycle;
\draw (2,1.5) node{$41$};
\draw (3,2)--(5,2)--(5,1)--(3,1)--cycle;
\draw (4,1.5) node{$43$};
\draw (5,2)--(7,2)--(7,1)--(5,1)--cycle;
\draw (6,1.5) node{$45$};
\draw (7,2)--(9,2)--(9,1)--(7,1)--cycle;
\draw (8,1.5) node{$47$};
\draw (0,1)--(2,1)--(2,0)--(0,0)--cycle;
\draw (1,0.5) node{$50$};
\draw (2,1)--(4,1)--(4,0)--(2,0)--cycle;
\draw (3,0.5) node{$52$};
\draw (4,1)--(6,1)--(6,0)--(4,0)--cycle;
\draw (5,0.5) node{$54$};
\draw (6,1)--(8,1)--(8,0)--(6,0)--cycle;
\draw (7,0.5) node{$56$};
\draw (8,1)--(10,1)--(10,0)--(8,0)--cycle;
\draw (9,0.5) node{$58$};
\end{tikzpicture}
\end{document}
_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
- Flo44Érudit
Merci à vous deux!
Vu que je n'ai pas le temps d'investir dans LaTeX, ce sera la solution basique (tableur). Je m'étais dit que quelqu'un aurait peut-être eu l'idée géniale d'en faire un en ligne, vu qu'on trouve déjà pas mal de choses.
Vu que je n'ai pas le temps d'investir dans LaTeX, ce sera la solution basique (tableur). Je m'étais dit que quelqu'un aurait peut-être eu l'idée géniale d'en faire un en ligne, vu qu'on trouve déjà pas mal de choses.
- ben2510Expert spécialisé
La façon de procéder avec un tableur est simple et efficace !
J'ai proposé du TikZ parce qu'avec le confinement et le travail à distance je deviens un pro du LaTeX (quinze heures par semaine à taper des diapos des polys et des corrigés, forcément...).
J'ai proposé du TikZ parce qu'avec le confinement et le travail à distance je deviens un pro du LaTeX (quinze heures par semaine à taper des diapos des polys et des corrigés, forcément...).
_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
- ycombeMonarque
Ton lien déconne à cause des [ et ].ben2510 a écrit:Si tu aimes le LaTeX et le Python,
voila une solution avec TikZ.
[url="http://www.pythontutor.com/visualize.html#code=print%28%22\\begin%7Btikzpicture%7D%22%29%0Afor%20i%20in%20range%281,6%29%3A%0A%20%20%20%20y%3D6-i%0A%20%20%20%20for%20x%20in%20range%285-i,5%2Bi,2%29%3A%0A%20%20%20%20%20%20%20%20print%28%22\\%22%2Bf%22draw%20%28%7Bx%7D,%7By%7D%29--%28%7Bx%2B2%7D,%7By%7D%29--%28%7Bx%2B2%7D,%7By-1%7D%29--%28%7Bx%7D,%7By-1%7D%29--cycle%3B%22%29%0A%20%20%20%20%20%20%20%20print%28%22\\%22%2Bf%22draw%20%28%7Bx%2B1%7D,%7By-1%7D.5%29%20node%22%2B%22%7B%22%2Bf%22%24%7Bi%7D%7Bx%7D%24%22%2B%22%7D%3B%22%29%0Aprint%28%22\\end%7Btikzpicture%7D%22%29&cumulative=false&curInstr=63&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=[]&textReferences=false"]générer le TikZ en Python[/url]
- Code:
\documentclass[10pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}
\begin{document}
\begin{tikzpicture}
\draw (4,5)--(6,5)--(6,4)--(4,4)--cycle;
\draw (5,4.5) node{$14$};
\draw (3,4)--(5,4)--(5,3)--(3,3)--cycle;
\draw (4,3.5) node{$23$};
\draw (5,4)--(7,4)--(7,3)--(5,3)--cycle;
\draw (6,3.5) node{$25$};
\draw (2,3)--(4,3)--(4,2)--(2,2)--cycle;
\draw (3,2.5) node{$32$};
\draw (4,3)--(6,3)--(6,2)--(4,2)--cycle;
\draw (5,2.5) node{$34$};
\draw (6,3)--(8,3)--(8,2)--(6,2)--cycle;
\draw (7,2.5) node{$36$};
\draw (1,2)--(3,2)--(3,1)--(1,1)--cycle;
\draw (2,1.5) node{$41$};
\draw (3,2)--(5,2)--(5,1)--(3,1)--cycle;
\draw (4,1.5) node{$43$};
\draw (5,2)--(7,2)--(7,1)--(5,1)--cycle;
\draw (6,1.5) node{$45$};
\draw (7,2)--(9,2)--(9,1)--(7,1)--cycle;
\draw (8,1.5) node{$47$};
\draw (0,1)--(2,1)--(2,0)--(0,0)--cycle;
\draw (1,0.5) node{$50$};
\draw (2,1)--(4,1)--(4,0)--(2,0)--cycle;
\draw (3,0.5) node{$52$};
\draw (4,1)--(6,1)--(6,0)--(4,0)--cycle;
\draw (5,0.5) node{$54$};
\draw (6,1)--(8,1)--(8,0)--(6,0)--cycle;
\draw (7,0.5) node{$56$};
\draw (8,1)--(10,1)--(10,0)--(8,0)--cycle;
\draw (9,0.5) node{$58$};
\end{tikzpicture}
\end{document}
Avec le "embed code' ça passe:
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ben2510Expert spécialisé
Merci !
_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
- ycombeMonarque
Accessoirement, tu peux utiliser des r-string pour éviter le double backslash et le combiner avec une f-string et employer le code utf8 pour les accolades à l'intérieur de la f-string:
- Code:
print(r"\begin{tikzpicture}")
for i in range(1,6):
y = 6-i
for x in range(5-i,5+i,2):
print( fr"\draw ({x},{y})--({x+2},{y})--({x+2},{y-1})--({x},{y-1})--cycle;")
print( f"\\draw ({x+1},{y-1}.5) node \u007b ${i}{x}$ \u007d ;")
print(r"\end{tikzpicture}")
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
Bon, j'ai un peu modifié le code histoire de gagner en souplesse
- Code:
def encadre(s):
s.insert(0, r"\begin{tikzpicture}")
s.append(r"\end{tikzpicture}")
return '\n'.join(s)
def generate_box(x, y):
return [ fr"\draw ({x},{y})--({x+2},{y})--({x+2},{y-1})--({x},{y-1})--cycle;" ]
def generate_node(x,y, no):
return [ f"\\draw ({x+1},{y-1}.5) node \u007b ${no}{x}$ \u007d ;" ]
def generate_ligne(y, nombre_lignes, no):
s = []
for x in range(nombre_lignes-no,nombre_lignes+no,2):
s += generate_box(x,y) + generate_node(x,y,no)
return s
def generate_pyramide(nombre_lignes):
s = []
for i in range(nombre_lignes):
y = nombre_lignes - i
s += generate_ligne(y, nombre_lignes, i+1)
return encadre(s)
print(generate_pyramide(8))
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
Évidemment, le problème suivant est de choisir les n cases (hauteur de la pyramide) qui donnent une solution complète.
Problème résolu sur papier, il faut que je passe au codage. Laissez-moi quelques jours.
Problème résolu sur papier, il faut que je passe au codage. Laissez-moi quelques jours.
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
Voilà, plus qu'à intégrer ça avec le générateur de cases en tikz qui est dessus.
La dernière ligne renvoie un dict comme:
{0: 5, 5: 5, 8: 7, 9: 5, 10: 7, 20: 105}
à lire comme numéro de case : valeur
(Cases numérotées en partant de 0 en bas à gauche et en allant toujours de gauche à droite sur les lignes, en remontant.)
La dernière ligne renvoie un dict comme:
{0: 5, 5: 5, 8: 7, 9: 5, 10: 7, 20: 105}
à lire comme numéro de case : valeur
(Cases numérotées en partant de 0 en bas à gauche et en allant toujours de gauche à droite sur les lignes, en remontant.)
- Spoiler:
- Code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed May 27 17:21:12 2020
@author: yves
"""
import numpy as np
import itertools
import random
class Pyramide():
# stolen in the net (choose)
#
def nCr(self, n, k):
"""
A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
"""
if 0 <= k <= n:
ntok = 1
ktok = 1
for t in range(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok
else:
return 0
def __init__(self, size):
if size < 4:
raise ValueError("Pyramide sans intérêt si taille < 5")
# size
self.n = size
# n lines of the matrix
self.n_lines = self.n*(self.n+1)//2
# calculation matrix from base line to all values
self.mat = np.empty((self.n_lines,self.n), dtype='int')
# used only to statistical fonctions
self.determinants = None
m_line = 0
for part in range(self.n,0,-1):
n_comb = self.n - part
for line in range(part):
for case in range(self.n):
self.mat[m_line, case] = self.nCr( n_comb, case - line)
m_line += 1
def get_random_pyramid(self, difficulty = 2, min=1, max = 9, *, seed = None):
"""
return a dict { number_of_case : value }
you can use as puzzle
"""
if difficulty < 1 or difficulty > 8:
raise ValueError("difficulty between 1 and 8")
elif difficulty > 3 and self.n == 4:
raise ValueError("size too low for difficulty")
# self.random_cases are cases to fill for the puzzle
self.random_cases = np.array(self.__choose_random__(difficulty, seed = seed))
self.random_cases.transpose()
# choose values for base line
self.base_solution = np.random.randint(min, max, size=(self.n,1))
# get values for all cases
self.solution = np.matmul(self.mat, self.base_solution)
# get index and values for selected cases
# the visible part of the puzzle
self.puzzle = { c: self.solution[c,0] for c in self.random_cases }
return self.puzzle
def __choose_random__(self, difficulty = 2, *, seed = None):
"""
choose at random cases to fill for given difficulty
"""
lines = list(range(self.n_lines))
random.seed(seed)
random.shuffle(lines)
iter_mat = itertools.combinations(lines, self.n)
det = 0
for l in iter_mat:
det = abs(round(np.linalg.det(self.mat[l,])))
if det == difficulty:
return tuple(sorted(l))
else:
raise ValueError("This difficulty was not found with that size")
#####
# statistical only calculations: all determinants
# for all choices of cases
# only det !=0 give a possible puzzle
# abs(determinant) is used as a difficulty level
#####
def __get_determinants__(self):
"""
list all determinants in self.determinants
can be long, 9min on my old core i7 for n=8
"""
lines = list(range(self.n_lines))
# random.shuffle(lines)
sel_mat = itertools.combinations(lines, self.n)
self.determinants = {}
for l in sel_mat:
#l = sorted(l)
det = abs(round(np.linalg.det(self.mat[l,])))
if det in self.determinants:
self.determinants[det].append(l)
else:
self.determinants[det] = [l]
def __nbr_cas__(self):
return self.nCr(self.n_lines, self.n_lines - self.n)
def __bilans__(self):
# can be long
if not self.determinants:
self.__get_determinants__()
if 0 in self.determinants:
n_zeros = len(self.determinants[0])
else:
n_zeros = 0
print(f"{self.__nbr_cas__()} choix possibles dont {n_zeros} impossibles.")
max_det = max(self.determinants.keys())
print(f"Déterminant maximal : {max_det}")
p = Pyramide(6)
# bon courage
print(p.get_random_pyramid(5))
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
Quelques stats avant que je termine le code (j'ai sorti R): que se passe-t-il si on veut vérifier toutes les possibilités pour choisir les n cases ?
On remarque bien l'explosion du nombre de cas à partir de n=7 et surtout 8, avec presque 1,2 millions de choix possibles pour n=7 et plus de trente millions pour n=8. Le temps de calcul va avec, long pour n=7 (22 secondes), insupportable pour n=8 (9 min).
Notez que c'est juste lorsque je fais calculer tous les cas. Pour générer juste une pyramide de la difficulté demandé, on va générer les matrices une par une jusqu'à ce qu'on obtienne le bon déterminant. C'est beaucoup plus rapide, même avec n=10 c'est quasi instantané.
On remarque bien l'explosion du nombre de cas à partir de n=7 et surtout 8, avec presque 1,2 millions de choix possibles pour n=7 et plus de trente millions pour n=8. Le temps de calcul va avec, long pour n=7 (22 secondes), insupportable pour n=8 (9 min).
Notez que c'est juste lorsque je fais calculer tous les cas. Pour générer juste une pyramide de la difficulté demandé, on va générer les matrices une par une jusqu'à ce qu'on obtienne le bon déterminant. C'est beaucoup plus rapide, même avec n=10 c'est quasi instantané.
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ben2510Expert spécialisé
Beau boulot ! Il n'y a plus qu'à tout réécrire en javascript pour mettre ça dans une page ouèbe.
_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
- ycombeMonarque
Attends, j'avais pas fini:
Plus qu'à ajouter la gestion des arguments en ligne de commande pour la taille, la difficulté, la sortie des solutions ou pas et on sera pas mal.
Plus qu'à ajouter la gestion des arguments en ligne de commande pour la taille, la difficulté, la sortie des solutions ou pas et on sera pas mal.
- Spoiler:
- Code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed May 27 17:21:12 2020
@author: yves
"""
import numpy as np
import itertools
import random
class PyramidePrinterTikz():
def __init__(self, pyramide):
self.size = pyramide.n
self.n_values = pyramide.n_lines
self.puzzle = pyramide.puzzle
self.solution = pyramide.solution
self.out = { 'puzzle' : "", 'solution' : "" }
self.print_solution = False
def print(self, puzzle=True, solution=True, *,filename = None):
if solution and self.solution is None:
solution = False
self.values = []
# on imprime le puzzle même si vide.
self.streams = ['puzzle']
self.streams += [ 'solution' ] if solution else []
file_mode = "w"
while self.streams:
if self.streams[0] == 'puzzle':
for k in range(self.n_values):
self.values.append(self.puzzle[k] if k in self.puzzle else '_')
elif self.streams[0] == 'solution':
self.values = [ int(n) for n in self.solution ]
# str will be type of puzzle values
for k in self.puzzle:
self.values[k] = str(self.values[k])
else:
self.values = None
self.initialize()
self.print_pyramide()
self.finalize()
if filename:
with open(filename, file_mode) as f:
f.write(self.out[self.streams[0]])
f.write("\n")
file_mode="a"
else:
print(self.out[self.streams[0]],"\n")
self.streams.pop(0)
def print_pyramide(self):
for i in range(self.size):
y = self.size - i
self.print_line(y, i+1)
def print_line(self, y, no):
for x in range(self.size-no,self.size+no,2):
self.print_box(x,y)
self.print_node(x,y)
def print_box(self, x, y):
self.__add_line_out__(fr"\draw ({x},{y})--({x+2},{y})--({x+2},{y-1})--({x},{y-1})--cycle;")
def print_node(self, x, y):
if not self.values:
return
value = self.values.pop()
if value == "_":
return
# puzzle
if type(value) is str:
color="[text=red]"
else:
color=""
self.__add_line_out__(f"\\draw ({x+1},{y-1}.5) node{color} \u007b ${value}$ \u007d ;")
def initialize(self):
self.__add_line_out__(f"%% {self.streams[0]}")
self.__add_line_out__(r"\begin{tikzpicture}")
def finalize(self):
self.__add_line_out__(r"\end{tikzpicture}")
def __add_line_out__(self, line):
self.out[self.streams[0]] += line + '\n'
class Pyramide():
# stolen in the net (choose)
#
def nCr(self, n, k):
"""
A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
"""
if 0 <= k <= n:
ntok = 1
ktok = 1
for t in range(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok # // casse la reconnaissance de code du site
else:
return 0
def __init__(self, size):
if size < 4:
raise ValueError("Pyramide sans intérêt si taille < 5")
# size
self.n = size
# n lines of the matrix
self.n_lines = self.n*(self.n+1)//2
# calculation matrix from base line to all values
self.mat = np.empty((self.n_lines,self.n), dtype='int')
# used only to statistical fonctions
self.determinants = None
m_line = 0
for part in range(self.n,0,-1):
n_comb = self.n - part
for line in range(part):
for case in range(self.n):
self.mat[m_line, case] = self.nCr( n_comb, case - line)
m_line += 1
self.solution = None
self.puzzle = {}
def get_size(self):
return self.n
def get_nbr_cases(self):
return self.n_lines
def get_random_pyramid(self, difficulty = 2, min=1, max = 9, *, seed = None):
"""
return a dict { number_of_case : value }
you can use as puzzle
"""
if difficulty < 1 or difficulty > 8:
raise ValueError("difficulty between 1 and 8")
elif difficulty > 3 and self.n == 4:
raise ValueError("size too low for difficulty")
# self.random_cases are cases to fill for the puzzle
self.random_cases = np.array(self.__choose_random__(difficulty, seed = seed))
self.random_cases.transpose()
# choose values for base line
self.base_solution = np.random.randint(min, max, size=(self.n,1))
# get values for all cases
self.solution = np.matmul(self.mat, self.base_solution)
# get index and values for selected cases
# the visible part of the puzzle
self.puzzle = { c: int(self.solution[c,0]) for c in self.random_cases }
return self.puzzle
def __choose_random__(self, difficulty = 2, *, seed = None):
"""
choose at random cases to fill for given difficulty
"""
lines = list(range(self.n_lines))
random.seed(seed)
random.shuffle(lines)
iter_mat = itertools.combinations(lines, self.n)
det = 0
for l in iter_mat:
det = abs(round(np.linalg.det(self.mat[l,])))
if det == difficulty:
return tuple(sorted(l))
else:
raise ValueError("This difficulty was not found with that size")
#####
# statistical only calculations: all determinants
# for all choices of cases
# only det !=0 give a possible puzzle
# abs(determinant) is used as a difficulty level
#####
def __get_determinants__(self):
"""
list all determinants in self.determinants
can be long, 9min on my old core i7 for n=8
"""
lines = list(range(self.n_lines))
# random.shuffle(lines)
sel_mat = itertools.combinations(lines, self.n)
self.determinants = {}
for l in sel_mat:
#l = sorted(l)
det = abs(round(np.linalg.det(self.mat[l,])))
if det in self.determinants:
self.determinants[det].append(l)
else:
self.determinants[det] = [l]
def __nbr_cas__(self):
return self.nCr(self.n_lines, self.n_lines - self.n)
def __bilans__(self):
# can be long
if not self.determinants:
self.__get_determinants__()
if 0 in self.determinants:
n_zeros = len(self.determinants[0])
else:
n_zeros = 0
print(f"{self.__nbr_cas__()} choix possibles dont {n_zeros} impossibles.")
max_det = max(self.determinants.keys())
print(f"Déterminant maximal : {max_det}")
p = Pyramide(6)
p.get_random_pyramid(5)
# bon courage
pr = PyramidePrinterTikz(p)
pr.print(filename='out6')
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
Facile: il n'y a qu'à écrire une classe PyramidePrinterXHTMLStrict qui fait ça.ben2510 a écrit:Beau boulot ! Il n'y a plus qu'à tout réécrire en javascript pour mettre ça dans une page ouèbe.
D'ailleurs, il faut reprendre ce code: une classe PyramidePrinter qui fait tous les calculs et reprend printer, et les sous classes TIKZ/HTML/etc... qui gèrent les parties dessin.
(Ça va faire un bel exercice pour des MPI, non? algèbre linéaire, numpy, programmation objet...):
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
- Spoiler:
Ça avance tranquille. J'ai inclus argparse pour lancer en ligne de commande. Les images ci-dessus viennent d'un pdf découpé par gimp, pdf créé à partir du fichier généré par:
- Code:
./pyramide.py -s 8 -d 1 -f out8 -l "\\bigskip\n" -m -5 -M 5
Les options étant:
- Code:
usage: pyramide.py [-h] [-s SIZE] [-d {1,2,3,4,5}] [-m MIN] [-M MAX] [-S SEED]
[-f FILENAME] [-t LATEX_SEPARATOR]
optional arguments:
-h, --help show this help message and exit
-s SIZE, --size SIZE Piramid size (4 or more)
-d {1,2,3,4,5}, --difficulty {1,2,3,4,5}
difficlty level (max 3 if size is 4)
-m MIN, --min MIN minimum number in base
-M MAX, --max MAX maximum number in base
-S SEED, --seed SEED Seed number for random generator
-f FILENAME, --filename FILENAME
output file
-t LATEX_SEPARATOR, --latex-separator LATEX_SEPARATOR
separator latex code betwwen puzzle and solution
- Vous voulez vraiment voir les 308 lignes de code ?:
Ça va finir coupé en petits morceaux comme module pour pip, je sens. Pas encore fait ça, ça me fera une expérience.
- Code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed May 27 17:21:12 2020
@author: yves
"""
import numpy as np
import itertools
import random
import argparse
import sys
class PyramidePrinter():
def __init__(self, pyramide):
self.size = pyramide.n
self.n_values = pyramide.n_lines
self.puzzle = pyramide.puzzle
self.solution = pyramide.solution
def print(self, puzzle=True, solution=True, **kwargs):
if solution and self.solution is None:
solution = False
self.values = []
# on imprime le puzzle même si vide.
self.streams = ['puzzle']
self.streams += [ 'solution' ] if solution else []
self.initialize_printer(**kwargs)
for stream in self.streams:
if stream == 'puzzle':
for k in range(self.n_values):
self.values.append(self.puzzle[k] if k in self.puzzle else '_')
elif stream == 'solution':
self.values = [ int(n) for n in self.solution ]
# str will be type of puzzle values
for k in self.puzzle:
self.values[k] = str(self.values[k])
else:
self.values = None
#print("Values: ", self.values)
self.initialize_pyramide(stream)
self.print_pyramide()
self.finalize_pyramide()
self.finalize_printer()
def initialize_printer(self, **kwargs):
"""
Initialisation code for the printer object
**kwargs are passer from self.printer
Implement in subclass
"""
raise NotImplementedError("Don't use directly this class !")
def finalize_printer(self):
"""
finalization code for the printer object
**kwargs are passer from self.printer
Implement in subclass
"""
raise NotImplementedError("Don't use directly this class !")
def initialize_pyrammide(self, stream):
"""
initialisation code for each pyramide to print
stream is 'puzzle' or 'solution'
"""
raise NotImplementedError("Don't use directly this class !")
def print_pyramide(self):
"""
Implement in the subclass
self.values as values to print, or '_'
self.size as size of the pyramide
self.current_stream is 'puzzle' or 'solution'
"""
raise NotImplementedError("Don't use directly this class !")
def finalize_pyramide(self):
"""
finalisation code for each pyramide to print
"""
raise NotImplementedError("Don't use directly this class !")
class PyramidePrinterTikz(PyramidePrinter):
def __init__(self, pyramide):
super().__init__(pyramide)
def initialize_printer(self, **kwargs):
self.current_stream = None
self.filename = kwargs.get('filename', None)
self.sep = kwargs.get('separator', "")
self.out = {}
for stream in self.streams:
self.out[stream] = ""
def finalize_printer(self):
with self.filename as f:
for stream in self.streams:
f.write(self.out[stream])
f.write("\n")
def initialize_pyramide(self,stream):
#add a seperator before each pyramide but first
if self.current_stream:
self.__add_line_out__(self.sep)
self.current_stream = stream
self.__add_line_out__(f"%% {stream}")
self.__add_line_out__(r"\begin{tikzpicture}")
def finalize_pyramide(self):
self.__add_line_out__(r"\end{tikzpicture}")
def print_pyramide(self):
for i in range(self.size):
y = self.size - i
self.__print_line__(y, i+1)
def __add_line_out__(self, line):
if line:
self.out[self.current_stream] += line + '\n'
def __print_line__(self, y, no):
for x in range(self.size-no,self.size+no,2):
self.__print_box__(x,y)
self.__print_node__(x,y)
def __print_box__(self, x, y):
self.__add_line_out__(fr"\draw ({x},{y})--({x+2},{y})--({x+2},{y-1})--({x},{y-1})--cycle;")
def __print_node__(self, x, y):
if not self.values:
return
value = self.values.pop()
if value == "_":
return
# puzzle
if type(value) is str:
color="[text=red]"
else:
color=""
self.__add_line_out__(f"\\draw ({x+1},{y-1}.5) node{color} \u007b ${value}$ \u007d ;")
class Pyramide():
# stolen in the net (choose)
#
def nCr(self, n, k):
"""
A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
"""
if 0 <= k <= n:
ntok = 1
ktok = 1
for t in range(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok
else:
return 0
def __init__(self, size):
if size < 4:
raise ValueError("Pyramid Size at least 4")
# size
self.n = size
# n lines of the matrix
self.n_lines = self.n*(self.n+1)//2
# calculation matrix from base line to all values
self.mat = np.empty((self.n_lines,self.n), dtype='int')
# used only to statistical fonctions
self.determinants = None
m_line = 0
for part in range(self.n,0,-1):
n_comb = self.n - part
for line in range(part):
for case in range(self.n):
self.mat[m_line, case] = self.nCr( n_comb, case - line)
m_line += 1
self.solution = None
self.puzzle = {}
def get_size(self):
return self.n
def get_nbr_cases(self):
return self.n_lines
def get_random_pyramid(self, difficulty = 2, min=1, max = 9, *, seed = None):
"""
return a dict { number_of_case : value }
you can use as puzzle
"""
if difficulty < 1 or difficulty > 8:
raise ValueError("difficulty between 1 and 8")
elif difficulty > 3 and self.n == 4:
raise ValueError("size too low for difficulty")
# self.random_cases are cases to fill for the puzzle
self.random_cases = np.array(self.__choose_random__(difficulty, seed = seed))
self.random_cases.transpose()
# choose values for base line
self.base_solution = np.random.randint(min, max+1, size=(self.n,1))
# get values for all cases
self.solution = np.matmul(self.mat, self.base_solution)
# get index and values for selected cases
# the visible part of the puzzle
self.puzzle = { c: int(self.solution[c,0]) for c in self.random_cases }
return self.puzzle
def __choose_random__(self, difficulty = 2, *, seed = None):
"""
choose at random cases to fill for given difficulty
"""
lines = list(range(self.n_lines))
random.seed(seed)
random.shuffle(lines)
iter_mat = itertools.combinations(lines, self.n)
det = 0
for l in iter_mat:
det = abs(round(np.linalg.det(self.mat[l,])))
if det == difficulty:
return tuple(sorted(l))
else:
raise ValueError("This difficulty was not found with that size")
#####
# statistical only calculations: all determinants
# for all choices of cases
# only det !=0 give a possible puzzle
# abs(determinant) is used as a difficulty level
#####
def __get_determinants__(self):
"""
list all determinants in self.determinants
can be long, 9min on my old core i7 for n=8
"""
lines = list(range(self.n_lines))
# random.shuffle(lines)
sel_mat = itertools.combinations(lines, self.n)
self.determinants = {}
for l in sel_mat:
#l = sorted(l)
det = abs(round(np.linalg.det(self.mat[l,])))
if det in self.determinants:
self.determinants[det].append(l)
else:
self.determinants[det] = [l]
def __nbr_cas__(self):
return self.nCr(self.n_lines, self.n_lines - self.n)
def __bilans__(self):
# can be long
if not self.determinants:
self.__get_determinants__()
if 0 in self.determinants:
n_zeros = len(self.determinants[0])
else:
n_zeros = 0
print(f"{self.__nbr_cas__()} choix possibles dont {n_zeros} impossibles.")
max_det = max(self.determinants.keys())
print(f"Déterminant maximal : {max_det}")
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--size", type=int, default=5,
help="Piramid size (4 or more)")
parser.add_argument("-d", "--difficulty", type=int, choices=range(1,6), default=2,
help="difficlty level (max 3 if size is 4)")
parser.add_argument("-m", "--min", type=int, default=0,
help="minimum number in base")
parser.add_argument("-M", "--max", type=int, default=9,
help="maximum number in base")
parser.add_argument("-S", "--seed", type=int,
help="Seed number for random generator")
parser.add_argument("-f", "--filename", type=argparse.FileType('w'), default=sys.stdout,
help="output file")
parser.add_argument("-l", "--latex-separator", type=str, default="",
help="separator latex code betwwen puzzle and solution")
args = parser.parse_args()
p = Pyramide(args.size)
p.get_random_pyramid(args.difficulty,args.min, args.max, seed=args.seed)
# bon courage
pr = PyramidePrinterTikz(p)
pr.print(filename=args.filename, separator=args.latex_separator)
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
Bon, j'ai commencé le nettoyage et la mise en propre pour inclusion dans PyPI.
Il manque encore un peu de doc.
https://framagit.org/ycombe/saqqarah
Il faut encore que je:
- remplace les initialize/finalize par des context managers.
- fasse une page de documentation
Une fois que ça sera fait, je le mets sur PyPI. Après je fais un printer qui crée directement une image avec PIL.
Je voulais l'appeler Imhotep, normal pour un générateur de pyramides. Mais c'était déjà pris. Alors j'ai mis Saqqarah comme nom.
Il manque encore un peu de doc.
https://framagit.org/ycombe/saqqarah
Il faut encore que je:
- remplace les initialize/finalize par des context managers.
- fasse une page de documentation
Une fois que ça sera fait, je le mets sur PyPI. Après je fais un printer qui crée directement une image avec PIL.
Je voulais l'appeler Imhotep, normal pour un générateur de pyramides. Mais c'était déjà pris. Alors j'ai mis Saqqarah comme nom.
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ben2510Expert spécialisé
Balèze, Ô Grand Scribe
_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
- ycombeMonarque
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
C'est fait: https://pypi.org/project/saqqarah/
Un simple
J'ai mis python >= 3.6 mais je ne suis pas sûr de tout que ça marche avec autre chose que python3.7. Il faut que je vérifie.
Edit: si ça trouve, ça marche avec python3.4... Non, il y a des f-strings donc python >= 3.6
Edit: : le mode image ne marche pas: il manque un ttf. Corrigé.
Un simple
- Code:
pip install saqqarah
J'ai mis python >= 3.6 mais je ne suis pas sûr de tout que ça marche avec autre chose que python3.7. Il faut que je vérifie.
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ycombeMonarque
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
- ben2510Expert spécialisé
Voila un exemple nettement plus simple que le précédent. Pas besoin d'écrire un algorithme de descente de gradient cette fois-ci.
_________________
On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison. Henri Poincaré La notion d'équation différentielle est le pivot de la conception scientifique du monde. Vladimir Arnold
- ycombeMonarque
Il faut nous montrer ça en détail.ben2510 a écrit:Voila un exemple nettement plus simple que le précédent. Pas besoin d'écrire un algorithme de descente de gradient cette fois-ci.
Le logiciel utilise un bête calcul matriciel, lui.
_________________
Assurbanipal: "Passant, mange, bois, divertis-toi ; tout le reste n’est rien".
Franck Ramus : "Les sciences de l'éducation à la française se font fort de produire un discours savant sur l'éducation, mais ce serait visiblement trop leur demander que de mettre leur discours à l'épreuve des faits".
Page 1 sur 3 • 1, 2, 3
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum