Entretien
Il y a longtemps, j'ai interviewé de nombreux candidats pour de nombreux postes de programmation graphique. Être un bon intervieweur est un travail difficile ; mes premières tentatives n’étaient pas géniales. Au fil du temps, j'ai posé cette question pour lancer une conversation.
Moi : Que faites-vous si un collègue vient vers vous et vous dit « Je dois dessiner un cercle ? »
- Candidat 0 : Je ne sais pas.
- Candidat 1 : Je ne sais pas. Une boussole?
- Candidat 2 : Hmmmm. J'imprimerais une petite lettre "o".
- Candidat 3 : La racine carrée devrait suffire.
- Candidat 4 : Les sinus et les cosinus devraient le faire.
- Candidat 5 : L'algorithme de dessin de cercles de Bresenham devrait le faire.
- Candidat 6 : Je leur dirais de chercher une fonction de bibliothèque, de leur montrer où se trouve la documentation. Mieux vaut réutiliser qu’inventer.
- Candidat 7 : Je dirais « Je ne sais pas. Pourquoi veux-tu dessiner un cercle ?" parce qu'ils n'ont peut-être pas vraiment besoin d'en dessiner un. Peut-être qu’ils ont besoin de savoir ce qu’il y a à l’intérieur du cercle en utilisant la racine carrée. Peut-être qu'ils ont besoin d'une ellipse. Une fois que nous avons décidé qu’un cercle dessiné est vraiment nécessaire, où est-il dessiné ? Sera-t-il rempli, uni ou avec un motif ? Il y a de fortes chances qu'il existe déjà une fonction pour faire cela, et qu'elle soit déjà bien déboguée. Vous n'avez probablement pas besoin de l'écrire vous-même, mais si vous le faites, utilisez des sinus et des cosinus et faites en sorte que la taille du pas soit fonction du rayon. À quelle vitesse cela doit-il être ? Selon l'appareil, Bresenham peut être approprié. Sur une imprimante, une petite lettre « o » peut fonctionner comme un marqueur et suffire.
Discussion
Les candidats 0,1,2,3,4,5 ont tous manqué la forêt. Si vous êtes l'intervieweur, assurez-vous de l'aider à voir l'autre personne dans la question, car cela représente la moitié de la question. Et si vous êtes candidat, faites attention aux questions en deux parties.
Si vous êtes la personne interviewée, ne vous arrêtez jamais là où le candidat 0 s'est arrêté. Les candidats 1 et 2 fournissent juste assez d'accroche pour que l'intervieweur pose une autre question. Si vous êtes l'intervieweur, n'oubliez pas que le candidat se trouve dans une situation stressante et a besoin d'un peu d'aide pour obtenir plus de détails.
Les candidats 3, 4 et 5 proposent chacun une solution technique, dont chacune peut fonctionner, mais aucune n'est toujours la meilleure. Si vous êtes le candidat, continuez à parler de votre réponse. Si vous êtes l'intervieweur, coachez-le : « est-ce que ce sera (rapide, sûr, correct, etc.) ?
Les candidats 6 et 7 se situent à des endroits différents sur l’échelle pragmatique. Davantage de questions et de discussions sont nécessaires pour déterminer la meilleure solution.
Réponses
La question de l'entretien ne consiste pas vraiment à tracer un cercle, mais si c'est pour cela que vous lisez encore, voici JSL pour les réponses 2,3,4,5,6.
Lettre minuscule o, trois façons
New Window( "Candidate 2, literal",
Graph Box(
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
Text( Center Justified, {50, 50}, "o" ) // "o" sits above the point
)
);
Text sits above the baseline.Text sits above the baseline.Text sits above the baseline.Text sits above the baseline.Text sits above the baseline.Le texte se trouve au-dessus de la ligne de base.
New Window( "Candidate 2, modified",
Graph Box(
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
markersize(10),
marker( markerstate("O"), {50, 50}) // capital "O" is somewhat centered
)
);
Using a marker with a capital O.Using a marker with a capital O.Using a marker with a capital O.Using a marker with a capital O.Using a marker with a capital O.Utiliser un marqueur avec un O majuscule.
New Window( "Candidate 2, reinvented",
Graph Box(
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
Marker Size( 100 ),
Marker( Marker State( 8 ), {50, 50} ) // bigger is thicker
)
);
If you can use a marker, then you can pick the circle symbol.If you can use a marker, then you can pick the circle symbol.If you can use a marker, then you can pick the circle symbol.If you can use a marker, then you can pick the circle symbol.If you can use a marker, then you can pick the circle symbol.Si vous pouvez utiliser un marqueur, vous pouvez choisir le symbole du cercle.
Racine carrée, deux façons
New Window( "Candidate 3, sqrt hard way",
Graph Box(
framesize( 300, 300 ),
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
// draw a circle at 50,50 with radius 30 using sqrt
// a lot of code, and not too pretty on the left and right
step=3; // to make the problem more obvious, use 1 to almost hide it
For( x = 0, x < 30, x += step,
// hyp = sqrt(x^2 + y^2)
// hyp^2 = x^2 + y^2
// hyp^2 - x^2 = y^2
y1 = Sqrt( 30 ^ 2 - x ^ 2 );
y2 = Sqrt( 30 ^ 2 - (x + step) ^ 2 );
// do all four quadrants in parallel
Line( {50 + x, 50 + y1}, {50 + (x + step), 50 + y2} );
Line( {50 - x, 50 + y1}, {50 - (x + step), 50 + y2} );
Line( {50 - x, 50 - y1}, {50 - (x + step), 50 - y2} );
Line( {50 + x, 50 - y1}, {50 + (x + step), 50 - y2} );
)
)
);
The sqrt approach looks rough on the left and right because of the equal-sized steps in x.The sqrt approach looks rough on the left and right because of the equal-sized steps in x.The sqrt approach looks rough on the left and right because of the equal-sized steps in x.The sqrt approach looks rough on the left and right because of the equal-sized steps in x.The sqrt approach looks rough on the left and right because of the equal-sized steps in x.L'approche sqrt semble approximative à gauche et à droite en raison des pas de taille égale dans x.
New Window( "Candidate 3, sqrt with YFunction",
Graph Box(
framesize( 300, 300 ),
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
// draw a circle at 50,50 with radius 30 using sqrt
// sqrt has two answers. Looks nice, thanks YFunction. Only a small gap.
Y Function( 50 + Sqrt( 30 ^ 2 - (x - 50) ^ 2 ), x );// top
Y Function( 50 - Sqrt( 30 ^ 2 - (x - 50) ^ 2 ), x );// bottom
)
);
The Y Function adjusts the x step size automatically.The Y Function adjusts the x step size automatically.The Y Function adjusts the x step size automatically.The Y Function adjusts the x step size automatically.The Y Function adjusts the x step size automatically.La fonction Y ajuste automatiquement la taille du pas x.
Sinus et cosinus
New Window( "Candidate 4, sin/cos with XYFunction",
Graph Box(
framesize( 300, 300 ),
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
// draw a circle at 50,50 with radius 30 using sin/cos
XY Function( 50 + 30 * Cos( t ), 50 + 30 * Sin( t ), t, Min( 0 ), Max( 2 * Pi() ) )
)
);
I really like the XYFunction for this parametric description of a circle.I really like the XYFunction for this parametric description of a circle.I really like the XYFunction for this parametric description of a circle.I really like the XYFunction for this parametric description of a circle.I really like the XYFunction for this parametric description of a circle.J'aime beaucoup la fonction XYFunction pour cette description paramétrique d'un cercle.
Bresenham
//Bresenham.
// using pixel functions (There is no reason I can think of to
// use this code; everything else will be faster! A long time
// ago there was no floating point arithmetic or sin/cos/sqrt
// and tricks like this were useful.)
drawCircle = Function( {xc, yc, x, y}, // not really pixels. this is not a good match for JMP!
Marker( Marker State( 0 ), {xc + x, yc + y} ); // invented for primitive hardware without
Marker( Marker State( 0 ), {xc - x, yc + y} ); // floating point.
Marker( Marker State( 0 ), {xc + x, yc - y} );
Marker( Marker State( 0 ), {xc - x, yc - y} );
Marker( Marker State( 0 ), {xc + y, yc + x} );
Marker( Marker State( 0 ), {xc - y, yc + x} );
Marker( Marker State( 0 ), {xc + y, yc - x} );
Marker( Marker State( 0 ), {xc - y, yc - x} );
);
circleBres = Function( {xc, yc, r}, // https://www.geeksforgeeks.org/bresenhams-circle-drawing-algorithm/
x = 0;
y = r;
d = 3 - 2 * r;
drawCircle( xc, yc, x, y );
While( y >= x,
x++;
If( d > 0,
y--;
d = d + 4 * (x - y) + 10;
,
d = d + 4 * x + 6
);
drawCircle( xc, yc, x, y );
);
);
New Window( "Candidate 5, really hard way using pixels",
Graph Box(
framesize( 900, 900 ),xscale(0,1000),yscale(0,1000),
xaxis( Add Ref Line( 500, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 500, "Solid", "Black", "", 1 ) ),
// draw a circle at 500,500 with radius 300
circleBres( 500, 500, 300 ),
text({300,700},"Zoom in for detail")
)
);
The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)Le but de l'algorithme de dessin de cercle de Bresenham est d'utiliser uniquement des nombres entiers et d'éviter de multiplier et de diviser ( *2 et *4 peuvent être des opérations de décalage.)
Zoomed in the pixels always step in either x or y or both.Zoomed in the pixels always step in either x or y or both.Zoomed in the pixels always step in either x or y or both.Zoomed in the pixels always step in either x or y or both.Zoomed in the pixels always step in either x or y or both.Le zoom sur les pixels avance toujours soit en x, soit en y, ou les deux.
Fonctions de la bibliothèque
New Window( "Candidate 6, Circle Function",
Graph Box(
xaxis( Show Major Grid( 1 ) ),
yaxis( Show Major Grid( 1 ) ),
Circle( {50, 50}, 30 )
)
);
The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.La fonction Cercle utilise la dimension Y et crée un cercle visiblement rond. Comme les axes ne sont pas isométriques, quelque chose semble étrange.
New Window( "Candidate 6, Circle on square paper",
Graph Box( framesize(400,400),
xaxis( Show Major Grid( 1 ) ),
yaxis( Show Major Grid( 1 ) ),
Circle( {50, 50}, 30 )
)
);
The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.Le menu contextuel du graphique, Size/Scale->SizeToIsometric effectuera automatiquement cet ajustement.
Vous préférerez peut-être la fonction ovale :
New Window( "Candidate 6, Oval function",
Graph Box( // framesize(600,400),
x=50;
y=50;
r=30;
Oval( x-r, y-r, x+r, y+r );
)
);
The Oval function has a clear API for the vertical and horizontal dimensions.The Oval function has a clear API for the vertical and horizontal dimensions.The Oval function has a clear API for the vertical and horizontal dimensions.The Oval function has a clear API for the vertical and horizontal dimensions.The Oval function has a clear API for the vertical and horizontal dimensions.La fonction Oval dispose d'une API claire pour les dimensions verticales et horizontales.
Hydraulique
I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.J'ai tracé un DVD ; la main du cyborg enseigne vraiment l'hydraulique, les leviers et l'assemblage des pièces.
J'ai passé janvier et février à aider un enfant de cinq ans à assembler ce Mega Cyborg Hand. Je recommanderais sept ans comme âge minimum raisonnable (tout comme la boîte) ; nous avons fait des séances de 10 à 15 minutes tous les deux jours environ. C'est une valeur incroyable pour environ 30 $. Le meilleur : en rentrant chez lui l'autre jour, le 5 ans aperçoit une excavatrice et me parle des vérins hydrauliques.
Huge! Actually too big for a five year old.Huge! Actually too big for a five year old.Huge! Actually too big for a five year old.Huge! Actually too big for a five year old.Huge! Actually too big for a five year old.Énorme! En fait, trop grand pour un enfant de cinq ans.