Leaderboard
Popular Content
Showing content with the highest reputation on 23/05/2014 in all areas
-
Salut, j'ai adoré cette vidéo, extrêmement bien faite à mon sens, je vous la partage donc.3 points
-
Salut à tous, J'ai fais une vidéo expliquant comment crée une machine virtuel avec VirtualBox développé par Oracle. J'ai effectuer cette virtualisation avec Ubuntu, un système d'exploitation gratuit. Toutes critiques fondées est bien évidemment accepté. PS: First movie Cordialement, Antoine.2 points
-
Bonjour à tous, Ce cours va être très court (oh ce jeu de mot!). En effet, je vais juste vous montrer comment faire un pointeur sur fonction. I- Pointeur sur fonction? Kesako? Un pointeur sur fonction, c'est simplement une manière d'appeler une fonction, en passant par un pointeur. Par exemple: void (*function_pointer)(char); function_pointer = &my_putchar; // Vous pouvez retrouver la fonction my_putchar sur le cours #1. function_pointer('A'); Le programme ci-dessus crée le pointeur sur fonction function_pointer, et lui définit l'adresse de my_putchar (qui permet d'afficher un caractère). Il affiche 'A'. II- Utilité? Un pointeur sur fonction permet d'appeler une fonction via un pointeur. Il est très souvent utilisé pour les tableaux de pointeurs sur fonction. Ce qui permet, par exemple, d'appeler une fonction en fonction d'une condition, sans avoir 40 000 if/else. Exemple de tableau de pointeurs sur fonction: #include <unistd.h> void my_putchar(char c) { write(1, &c, 1); } void my_putstr(char *str) { while(*str) my_putchar(*(str++)); } void aff_help() { my_putstr("Commandes:\ncoucou: affiche salut\ndada: affiche dadi\npopo affiche caca"); } void aff_coucou() { my_putstr("salut\n"); } void aff_dada() { my_putstr("dadi\n"); } void aff_popo() { my_putstr("caca\n"); } void do_cmd(char *cmd) { void (*fptr[])() = {&aff_popo, &aff_dada, &aff_coucou}; char cmds[] = {"popo", "dada", "coucou"}; int i = -1; while (++i < 3) { if (!strcmp(cmds[i], cmd)) { fptr(i)(); return ; } } my_putstr("Commande introuvable."); } int main(int ac, char **av) { int readed; char buffer[4096]; my_putstr("Entrez votre commande. Utilisez CTRL+D pour quitter\n"); while ((readed = read(0, buffer, 4095)) != -1) { buffer[readed] = '\0'; do_cmd(buffer); } return (0); } III- Déclaration et appel. Enfin, voyons comment déclarer un pointeur sur fonction, puis comment lui définir une fonction. Déclarons notre pointeur. Forme de déclaration: typage_renvoyé_par_la_fonction (*nom_pointeur)(arguments_pris_par_la_fonction); Par exemple, pour printf: int (*myptr)(char *, ...); // oui, les ... sont un type. Il existe une fonction qui permet de récupérer une infinité d'args dans une fonction, mais je vousl’expliquerais dans un prochain cours! // Assignation myptr = &printf; // Utilisation myptr("Salut tout le %s", "monde!\n"); Voilà. Vous l'aurez compris, les pointeurs sur fonctions sont très, TRES utilisés dans le monde du développement. Il est donc important de savoir les utiliser, pour apprendre à gagner des lignes. Je vous dis a bientôt pour un prochain cours! Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr2 points
-
Bonjour à tous, Donc comme si bien dit dans mon titre je vais vous expliquer comment faire un système de bbcode en php. Et pour ceux qui ne savent pas ce qu'est le bbcode c'est un système de balise utilisé principalement sur les forums par exemple ici si vous voulez mettre un image avec un lien (si comme moi vous écrivez le bbcode à la main à la place d'utiliser l'interface) vous aurez un "code" comme celui-ci: [url=http://mon_utrl/][img=mon_image.png][/url] mais une fois traité il s'affichera sous une forme html: <a href="http://mon_url/" target="_blank"> <img src="mon_image.png" border="0" /> </a> ps: dans mon contexte les liens s'ouvrent dans un onglet et le desactive les bords pour IE Pourquoi ne pas laisser le code html aux utilisateurs/clients? Parce que celà fait une faille XSS (plus d'info sur ce topic) même si vous pouvez aussi en désactiver/activer certaines seulement. Je vais donc vous expliquer comment faire: - une balise orpheline (ex: [ img=], elle n'a aucune fermeture) - une balise non-orpheline (ex: [ code] - une balise non-orpheline + paramètre (ex: [ url=], il y a un paramètre en plus dans la balise) Donc pour faire notre bbcode vous allons utiliser ce qui s'appel des expressions régulières (aussi appelé "motif de recherche"), un truc que personnellement je n'aime pas car je me trompe souvent... Et donc une expression c'est en réalité une structure dans un texte (par exemple) on peut donc analyser s'il y a des chiffres, une chaîne de caractères ou autre, c'est souvent utilisé pour les e-mails pour voir si ce que vous avez entré ressemble à un e-mail, je ferais donc peut-être (si j'ai le courage un topic sur ça, sinon je connais un site assez bien. Bref donc nous allons commencer par une balise orpheline: // Contexte: J'ai fais une shoutbox et je mettre en place une balise [ img=] donc <img... en html $msg = "Bonjour! [img=heart.gif]"; $bb = '#\[ img=(.+)\]#iUs'; $htm = '<img src="$1" border="0" />'; $msg = preg_replace($bb, $htm, $msg); Donc l'expression: '#\#iUs' - Elle est délimité par des # - On utilise les antislashes ("\") avant certains caractères car ils peuvent être utilisé pour la structure (expression), caractères tels "[", "]", "(", ")", ... - "(.+)" : - - les parenthèses "()" symbolise un groupement littéral - - le point (".") symbolise qu'il peut s'agir de n'importe quel caractère et le plus ("+) symbolise qu'il peut y avoir 1 ou plusieurs caractères - "#iUs' : - - "i" effectuer une recherche insensible à la casse (par de différence entre une lettre majuscule et une minuscule). - - "U" cette option inverse la tendance à la gourmandise des expressions rationnelles. - - "s" permet au point "." de correspondre à encore plus de caractères et/ou un retour à la ligne. > Documentation PHP::Options de recherche Maintenant une balise pour center donc [centre][/centre] devient <center></center>, je vais un peux compacter le code pour avoir plus simple: $msg = "[centre]Coucou![/centre]"; $msg = preg_replace('#\[centre\](.+)\[\/centre\]#iUs', '<center>$1</center>', $msg); Il a donc suffit de déplacer "(.+)" et pour ceux qui n'avait pas encore compris la partie trouvée ici va remplacer le "$1", il sagit en réalité d'un tableau donc quand vous cherchez plusieurs expressions vous avez donc "$2", "$3",.. qui arrive. Nous allons donc maintenant avoir une balise avec un paramètre et pour complexer un peut on va dire que le paramètre est obligatoirement un chiffre décimal ^-^ // balise [taille=][/taille] remplacée par <font size=""></font> $msg = "[taille=5]Hello World! [/taille]"; $msg = preg_replace('#\[taille=(\d+)\](.+)\[\/taille\]#iUs', '<font size="$1">$2</font>', $msg); Comme vous le voyait j'ai mis la mettre "\d" à la place d'un "." donc à la place de chercher n'importe quel caractère je dis que c'est un chiffre décimal et le "+" spécifie qu'il peut-être composé de plusieurs chiffres même si je pense que font-size ne peut prendre que une valeur entre 1 et 5 j'aurais pu mettre directement "([1-2-3-4-5])" mais bon je ferais une explication plus détaillée dans un prochain topic PS: pour les smileys c'est un simple str_replace(): str_replace(":D", "<img src=\"images/smiley.gif\" />", $msg); PPS: et si vous avez plusieurs balise directement vous pouvez faire un tableau (si vous voulez vous pouvez mettre par exemple $htm[0] = "<b>$1</b>"; et donc pour reprendre toutes les balises faites + anti-faille XSS dans une fonction: function BBCode($msg = '') { $msg = htmlentities($msg); // suprresion des caractères spéciaux (html), à placer avant les modifications sinon vous affichez le message avec les balises (en lisible) $bb = array( '#\[img=(.+)\]#iUs', '#\[centre\](.+)\[\/centre\]#iUs', '#\[taille=(\d+)\](.+)\[\/taille\]#iUs', '#\[url=(\.*)\](.+)\[\/taille\]#iUs' ); $htm = array( '<img src="$1" border="0" />', '<center>$1</center>', '<font size="$1">$2</font>', '<a src="$1" target="_blank">$2</a>' ); return preg_replace($bb, $htm, $msg); } echo BBCode("[centre]<b>XSS</b>[/centre]"); /!\j'ai mis des espaces dans les balises pour pouvoir publier (ex: "[ img]")! Bonne programmation à tous! Cordialement, Mars0731 point
-
Salut à tous, Je suis en train de revoir totalement ma lib réseau. J'ai changé pas mal de principes. Entres autre, j'ai ajouté la possibilité d'avoir de l'Asynchrone, ce qui n'était pas possible avec l'ancienne lib. La nouvelle lib est faite pour fournir plusieurs outils, et pour fonctionner aussi bien sur Linux que sur Mac et Windows! Pour l'instant elle est en état de développement, mais plusieurs objets sont déjà fonctionnels. Voici le nouveau git qui lui est dédié: https://github.com/AlexMog/LibNet Une documentation HTML et LaTeX est disponible dans le dossier doc ou ici: http://alexmog.labs-epimars.eu/projets/mognetwork-doc/doc/html/ N'hésitez pas à la tester et à me faire des retours! Enjoy! Mog.1 point
-
Hey ! Un nouveau album de EH!DE est sortit récemment (cette semaine) Vous avez un avant gout ici : https://www.youtube.com/watch?v=FmH6i-sSi4Q&feature=youtu.be&a Je l'ai upload sur mon dropbox si y en a qui le veulent https://www.dropbox.com/sh/23phkf9qif69cvn/AAA_CP5Kd3aAYKvZ4FCqScEpa1 point
-
Bonjour à tous, Bienvenue dans ce 4ième cours sur la programmation en C. Aujourd'hui, nous allons voir un point intéréssent de notre programme, et un point clé en C: les Arguments de lancement, et les allocations dynamiques. I- Qu'est-ce qu'un argument de lancement? Un argument de lancement est une string ajoutée au lancement du programme permettant de faire passer ladite string au programme (string = chaine de caractères). Ainsi, si je lance le programme avec cette ligne de commande: mon programme recevra comme argument 1 : "mon_argument". (En faite, d'une façon générale, les arguments sont gérés par les shells qui lancent le programme. C'est une convention de programmation). Quelques exemples d'utilisations d'arguments: Les commandes unix utilisent très souvent les arguments: et peuvent donc permettre de faire passer une valeur, ou même un chemin à son programme (bah oui, c'est des Strings (tableaux de caractères). Bon, passons à la pratique: II- Récupérer des arguments de lancement Nous avions vu la structure basique d'un main en C: int main(void) { } Eh bien, je ne vous ai pas dit la vérité sur cette fonction! En effet, main peut prendre un void pour argument (et donc ne prendre aucun arguments), ou bien prendre un int, et un char **. Le véritable prototypage de la fonction main est donc: int main(int argc, char **argv) { } En voyant ça, vous allez me dire "dis donc, j'ai mal à la tête, y'a un ** dans ton code!" Eh bien ne vous inquiétez pas, il s'agit d'un tableau de chaines de caractères.Prenons pour exemple ce programme lancé comme ceci: coucou arg1 arg2 arg3 je suis fou Eh bien, nous pouvons récupérer les arguments de ce programme de la façon suivante: /* ** Je re-crée les fonctions d'affichage. Voir cours #1 et #2 */ void my_putchar(char c) { write(1, &c, 1); } void my_putstr(char *str) { while(*str) my_putchar(*(str++)); } int main(int argc, char **argv) { my_putstr(argv[0]); // Affichera my_putstr(argv[1]); // Affichera my_putstr(argv[2]); // Affichera my_putstr(argv[3]); // Affichera my_putstr(argv[4]); // Affichera my_putstr(argv[5]); // Affichera my_putstr(argv[6]); // Affichera return (0); } Nous butons à présent sur un problème, ré-utilisons le programme précédent, mais supprimons tous, ou un des arguments: Eh oui, comme vous le voyez, nous essayons d'accéder à la valeur d'un tableau qui n'existe pas, ce qui provoque une erreur d'accès en mémoire. Pour remédier à cela, les développeurs nous ont rajoutés "argc". Pour mieux vous faire comprendre, je vais vous définir exactement ce que signifie argc et argv: ArgC est un couplage entre les mots: Argument et Count, il s'agit donc du nombre d'arguments qui ont été passés en paramètres. ArgV est un couplage entre les mots: Argument et Value, il s'agit donc des valeurs de ces dits arguments. Maintenant que vous avez le nombre d'arguments, vous pouvez vérifier que le nombre d'arguments est correcte avant de l'afficher: int main(int argc, char **argv) { if (argc > 1) my_putstr(argv[1]); return (0); } argv[0] sera toujours présent, puisqu'il s'agit du tout premier argument, qui est vital pour lancer le programme (il s'agit plus exactement de la commande utilisée pour lancer le programme). Passons à présent à la partie complexe de ce cours: les allocations dynamiques. III- Les allocations dynamiques L'allocation dynamique, c'est l'art de savoir utiliser sa RAM et les répercussions de l'alloc sur celle-ci. Nous avions vu précédemment que pour pouvoir avoir une chaine de caractère avec une certaine taille, nous devions définir un tableau de caractères, avec une taille FIXE. Comme ceci: char mon_tableau[talle_de_mon_tableau]; Là est le problème, imaginons que nous devions modifier notre chaine, en lui imposant une taille plus grande: SegFault. Eh bien, la solution, c'est d'utiliser l'allocation dynamique: Au lieu de stocker notre chaine dans la stack, stockons la dans la RAM! (ce qui nous permet d'avoir plus d'espace, d'ailleurs! (généralement, la stack est limitée à quelques Ko, alors que la RAM non)) Vous comprenez donc qu'il est dangereux d'utiliser malloc de façon idiote: dans une boucle infinie par exemple... Puisque vous allez remplir votre RAM! Prenons un exemple simple: J'ai un programme qui connaît la taille d'une chaine de caractère, et je dois la stocker dans une variable: int main(void) { int lenght = 300000; // Oui, notre chaine est très longue } Si je tentais de déclarer un tableau statique de char de taille 300 000, il y aura énormément de chances pour que mon programme segfault dès le lancement. C'est problématique, en effet. Tentons donc d’allouer un emplacement dans la ram pour cette chaine: int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); } Tiens, ça marche! Lisons un peu mieux le man de malloc: en cas d'erreur, malloc retourne NULL. Nous allons donc vérifier si il y a eu une erreur (pour éviter le segfault): int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } } Bon, nous avons donc alloué un emplacement de type char* (donc tableau de caractères) dans notre ram, avec une taille de 300 000 cases! Cool! Nous pouvons donc remplire "ptr" exactement comme un tableau (case par case, voir cours sur les chaines de caractères). ATTENTION: ptr est un POINTEUR. Si vous modifiez son adresse, vous perdez l'ancienne adresse allouée! Donc ceci: int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } ptr = "coucou"; } est interdit et stupide (ne rigolez pas, les profs de programmation font souvent l'erreur!). Bon, c'est bien, nous avons alloué de la mémoire, mais bon, c 'est pas cool pour la RAM, on ne la vide jamais, il va falloir la vider! Pour la vider, la fonction "free" est là pour nous aider! Voilà mon programme une fois la fonction "free" utilisée: int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } free(ptr); } Tout marche! Cool! ATTENTION: pour bien vous montrer que modifier un pointeur est une mauvaise idée, tentez de faire ceci: int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } ptr = "coucou"; free(ptr); } Hop, vous tomberez sur une erreur qui se nomme "glibC" et qui corresponds à une erreur de pointage, la fonction "free" vous hurle dessus comme quoi votre pointeur ne pointe pas sur une zone allouée. Pour vous montrer que mon code fonctionne, je vais afficher ma chaine de caractère, qui fera l'alphabet avec 300 000 lettres! int main(void) { char *ptr; int i; i = 0; j = 0; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } while(i < 300000) { ptr[i] = j + 'a'; i = i + 1; j = j + 1; if (j + 'a' >= 'z') j = 0; } ptr[i] = '\0'; // NE PAS OUBLIER LA FIN DE LA CHAINE (voir cours sur les chaines de caractères) my_putstr(ptr); free(ptr); } Et voilà, vous savez à présent utiliser les allocations dynamiques! A bientôt pour le prochain cours! Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr1 point
-
1 point
-
J'ai pas compris le PS, mais en fait, mieux vaut traduire fichier par fichier, donc tu extrais un fichier, puis une fois modifié tu le glisse a nouveau dans le pbo depuis pbo manager1 point
-
Je suis témoin, la vidéo était "supprimée par l'utilisateur". PS: Modifié par FaKe77, il y a un jour. *spotted*1 point
-
Bonjour a tous ! Cette suite de tutoriel va vous expliquez comment faire une IA basique pour des pnj que vous pourrez adapter pour des jeux simples(non ce n'est pas une super grosse IA de la mort qui tue qui va faire vos problèmes de math toute seule). Dans la première partie du tutoriel, nous allons voir une partie fondamentale des IA dans les jeux vidéos : le pathfinding. Le code du pathfinding était trop long pour être expliqué dans un seul tutoriel, le premier traitera de la théorie et le deuxième de la pratique. Le pathfinding, qu'est ce que c'est ? Le pathfinding c'est le fait de dire a une personne : tu vas du point A au point B en évitant les obstacles. (c'est mieux que de se prendre les murs non ? ) Pour le pathfinding, nous allons mettre en place un algorithme A*, qui est très célèbre et qui peut être utilisé un peu partout, surtout dans le jeu utilisant un système de grille(starcraft, zelda etc...) A* tiens son nom de la recherche "en étoile" qu'il fait : pour chaque case, il va regarder celles d'autour qui n'ont pas été déjà exploré et va dire : celle la elle est plus loin de la case de départ que la précédente. petite image : Le 0 correspond au début. Plus on s'éloigne du 0, plus le coût (ou le poids, c'est la même chose) augmente. Le but, c'est de prendre le chemin, qui possède le plus faible coût. Par exemple, si vous voulez partir du point (0, 3) -> le 4eme point tout en haut a gauche, vous n'allez pas partir carrément a gauche, faire X fois le tour du gros truc noir, non ? Vous allez simplement prendre le chemin le plus court. Pour réaliser donc ce merveilleux pathfinding, vous allez donc partir du début (le point (7, 6)) et regarder autour, si ce bloc n'est pas un mur. Vous augmenter alors le coût du déplacement pour cette case, puis on refait cela jusqu’à ce qu'on trouve la fin voulu ou jusqu’à ce qu'il n'y ai plus de possibilité de passer car tous les blocs ont été explorés, il n'y a donc pas de possibilité d'aller du point A au point B. Puis on part de la fin et on passe par les blocs qui ont le plus faible coût. Pour réaliser cela, on commence par créer une file (oui je parle enfin de code). Une file est une structure de données qui permet de mettre des variables l'une après l'autre. La première donnée qui rentre dans la file est la première à sortir. Pour ceux qui ne savent pas ce que c'est : Donc ont la créer, cette file et on met, si ce n'est pas des murs, et s'il n'ont pas été déjà explorés,la position des blocs d’à coté, tout a la fin. A chaque tour de boucle, ont prend la première position et on refait la même chose. Pour les minecraftien, c'est comme l'eau qui coule déjà sur la case la plus proche, puis sur celles plus éloignées. Quand on a trouvé la fin, la où le pnj par exemple veut aller, on arrête, ou alors quand il n'y a plus de blocs a explorer, alors le pnj est triste car il ne peut pas y aller. Si on a trouvé la fin, on met alors dans une pile, (les dernières données qui arrivent dedans seront les premières à sortir), car le chemin doit être pris dans le sens contraire où l'on va. On cherche alors, a partir de la fin, la case autour d'elle qui a le plus faible coût, puis on enregistre sa position et on mets la direction contraire (n'oublier pas que le pnj va parcourir le chemin dans l'autre sens) dans la pile et on refait ça jusqu’à ce qu'on trouve le début. Et voila vous pouvez maintenant, grâce à ces explication créer vous même votre pathfinding, ou alors attendre le prochain tutoriel qui ne devrait pas tarder a suivre. En utilisant uniquement le pathfinding et intelligemment vous pouvez déjà créer un planning pour chaque pnj, ce qui va permettre de rendre une ville plus vivante (je pense surtout au village pnj de zelda qui sont toujours au même endroit, c'est un peu triste non ?).1 point
-
Ce tutoriel n'est pas destiné au débutants, mais plutôt a ceux qui ont déjà de l’expérience en C# ou VB.NET DLL ... what ? Les DLLs (Dynamic-Link Library) sont des fichiers non-exécutables, qui contiennent des fonctions pouvant être utilisée par d'autres applications. Windows fonctionne justement avec des DLLs (%windir%\system32\ pour ceux qui voudrait les voir). Les principales sont : -user32.dll (User inferface (MessageBox, Bouttons, etc ...)) -kernel32.dll (Fichiers, Mémoire, Processus/threads etc...) -gdi32.dll (Graphiques) Ces DLL forment ce qu'on appelle l'API* Windows, ou l'API* Win32. *API : Application Programming Interface NB: Il y a aussi ntdll.dll, qui contient l'API Native de Windows. Dans ce tutoriel je vais donc vous apprendre a importer les fonctions FindWindow et FlashWindow, exportées par user32.dll . DLLImport Pour importer ces fonctions, on va utiliser DLLImport, il requiert la classe DLLImportAttribute, dans le namespace System.Runtime.InteropServices : using System.Runtime.InteropServices; Description des paramètres : -string dllName : Le chemin vers la DLL, et son nom. (On va utiliser une DLL de windows donc on n'a pas besoin de spécifier le chemin) -bool BestFitMappig (par défaut true) : Permet de convertir les caractères UNICODE en ANSI, si il est true alors la conversion utilise le caractère ANSI le plus proche (best fit). -CallingConvention CallingConvention (par défaut CallingConvention.StdCall/Winapi) : Un membre de l'enum CallingConvention, c'est assez low-level, donc je ne vais pas l'expliquer ici, vous pouvez lire la doc si vous en avez envie. -CharSet CharSet (par défaut CharSet.Ansi) : En fait certaines fonctions ont deux types. Par exemple MessageBoxA, et MessageBoxW. Pour importer MessageBoxA il faut utiliser Charset.Ansi, et pour MessageBoxW, Charset.Unicode. , L'Ansi, sauvegarde chaque caractère dans un byte, ce qui fait qu'il n'y a que 256 caractère disponibles (dictionnaires "basique" : francais/anglais ...), Charset.Unicode utilise deux bytes (DBCS), ce qui permet d’accéder a 65,536 (2562) caractères. (arabe/chinois/coréen etc..) -string EntryPoint : Le nom de la fonction que vous voulez importer. -bool ExactSpelling (par défaut false en C# mais true en VB) : Si true, vous devez nommer la fonction avec son nom exact (en incluant le A/W, si nécessaire). -bool PreserveSig (par défaut true) : Quand c'est true, la fonction retourne un integer, et quand c'est false, elle retourne une void. Quand une void autre que S_OK (aussi appelé 0, NULL, ERROR_SUCCESS), une exception est lancée. L'exception correspond au code d'erreur. Si la fonction retourne un int autre que 0, vous pouvez gérer l'erreur comme vous le souhaitez. -bool SetLastError (par défaut false) : Si y'a une erreur durant l'utilisation de la fonction, on peut utiliser Marshal.GetLastWin32Error pour obtenir le code de l'erreur (error code) -bool ThrowOnUnmappableChar (par défaut false) : Si c'est a true et qu'une erreur survient durant la conversion des caractères d'UNICODE a ANSI, ça envoie une exception. Sinon ça remplace le caractère par un '?'. Oui y'a beaucoup de paramètres, mais ils sont rarement tous utilisé en même temps. Plateform Invoke DLLImport fait partie de la plateforme Invoke (PInvoke). Pour trouver les prototypes des fonctions qu'on veut utiliser, il faut se rendre sur le Microsoft Developer Network (MSDN). Par exemple pour FindWindow, le prototype est : (en C) HWND WINAPI FindWindow( _In_opt_ LPCTSTR lpClassName, _In_opt_ LPCTSTR lpWindowName ); Mais on ne peut pas utiliser les types des lib C en C# ... Donc on doit les 'traduire'. Un superbe site pour ça : pinvoke.net Attention ! Ce site ne contient pas les prototypes de TOUTE les fonctions, n’hésitez pas a utiliser Google. Pour FindWindow le prototype serait donc : static extern IntPtr FindWindow(string lpClassName, string lpWindowName); Un peu de pratique ... Ouvrez Visual Studio, on va commencer a coder. (ah bah enfin ... ) Ouvrez aussi une application ayant un titre facile a écrire, j'utiliserait Paint. Comme dit précédemment : using System.Runtime.InteropServices; // Le 'DLLImport' est habituellement placé au début d'une classe, ou encore dans une classe spécifique. [DLLImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); //On utilisera lpWindowName, lpClassName restera null. [DllImport("user32.dll", SetLastError = true)] static extern bool FlashWindow(IntPtr hwnd, bool bInvert); //hwnd est l'handle (quelque chose que Windows utilise pour identifier des objets) de la fenêtre, qu'on récupère grâce a FindWindow. Puis après on fait notre propre code : string sWindowName = "Untitled - Paint"; IntPtr hWindow = FindWindow(null,sWindowName); // Je préfère utiliser le nom de la fenêtre, donc je place le premier argument a null. int error = Marshal.GetLastWin32Error(); // Un peu d'error-checking, la liste des ErrorCodes peut être trouvée ici : SystemErrorCodes if (error == 0) { FlashWindow(hWindow, true); error = Marshal.GetLastWin32Error(); if (error == 0) Console.WriteLine("{0} flashed !", sWindowName); else Console.WriteLine("ErrorCode = {0}", error); } else Console.WriteLine("ErrorCode = {0}", error); // Si il y a une erreur, affiche l'erreur. End Bon bah voila, je pense que j'ai tout dit sur les bases du DLLImport. Pour plus de lecture : DLLImport Attribute Je n'ai montré que deux API (fonctions dans les DLL de windows), il y en a DES CENTAINES, liste disponible sur le MSDN : Windows API Index Petit projet qui montre quelques trucs possible avec l'api Windows : -WindowsControl.exe (scan VirusTotal) -Source (sans l’exécutable, vous devez le compiler vous-même) Si vous avez des questions, des commentaires etc. , n’hésitez pas a les poster ici. En espérant que ça vous aie plu, Davy.1 point
-
Bonjour à vous, Dans ce cours, nous allons voir à quoi corresponds un fichier header, ainsi que comment créer une librairie, et enfin, les structures! I- Qu'est-ce qu'une lib? Une lib, aussi nommée librairie (dynamique ou statique) est un fichier binaire contenant une liste de fonctions prédéfinies. Je vais vous donner un exemple de son utilisation, et pourquoi il est bon de créer une lib! Imaginons que vous avez créé plusieurs fonctions, il vous serait pratique de les ré-utiliser dans un autre programme! Malheureusement, la compilation est très longue si il y a beaucoup de fonctions. La lib est donc là pour deux choses: partager des fonctions sur diverses programmes, et éviter une compilation inutile sur des fonctions déjà près compilées. Pour mieux vous faire comprendre tout cela, créons trois fichiers distincts: main.c: int main(void) { my_putstr("coucou\n"); return (0); } my_putchar.c: void my_putchar(char c) { write(1, &c, 1); } my_putstr.c: void my_putstr(char *str) { while(*str) my_putchar(*(str++)); } Tentons à présent de compiler main.c: Hum.. notre linker nous gueule dessus en nous disant qu'il est impossible de trouver la fonction "my_putstr". C'est normal! my_putstr n'a pas été compilée avec notre main. Elle ne fais donc pas partie du programme. Maintenant, tentons de compiler tous nos fichiers en même temps: Ah! Là ça marche! On a notre a.out qui est bien créé, et qui affiche bien "coucou".C'est un bon point, mais nous ne sommes pas avancés, j'ai envie de réutiliser my_putchar et my_putstr dans mes autres programmes, je vais tenter des les compiler pour voir si je peux les ré-utiliser sans avoir à les recompiler! Hum... Mon linker me dit cette fois-ci qu'aucun main n'a été trouvé... Je ne peux donc pas compiler mes fonctions séparément? Eh bien si! Il a une solution, les transformer en fichiers binaires non exécutables (aussi appelées lib), leur extentions est généralement .a pour un rassemblement de mini-libs, et .o pour les fichiers de fonctions de cette lib (pour résumer, les .o sont les briques, et .a est une partie du mur ! On utilise les briques pour construire cette partie). Créons donc nos .o! (man cc pour plus d'informations) Voila! Je découvre my_putchar.o et my_putstr.o, tentez la commande "file my_putchar.o" pour voir qu'il s'agit bien d'un fichier binaire non exécutable. C'est cool, mais pour l'instant mes fichiers sont séparés, j'aimerais bien tous les avoir dans un même "packetage" pour éviter de me trimballer 40 fichiers par programmes. Eh bien, nous allons utiliser notre linker (et non plus notre compilateur) pour tous les liés dans un même package, un véritable fichier lib: un fichier .a. Nous l'appellerons libmy.a: Pour créer notre lib, voici la commande linker (je vous laisse le soin de lire le man de celle-ci): On peux en faite considérer les .o comme des briques, et les .a comme le ciment qui va maintenir ces briques sur le programme. Nous avons enfin notre lib! Tentons à présent de compiler main.c avec notre lib (je vous laisse, encore une fois, le soin de lire le man de gcc): Hop! Nous avons notre a.out fonctionnel! Vous savez à présent créer vos propres librairies! II- Les fichiers Header Nous avons vu précédemment comment créer notre propre librairie, mais néanmoins, nous avons, de temps à autres, des warnings qui apparaissent lors de notre compilation, voir même des erreurs car notre compilateur ne connaît pas les fonctions qu'il utilise.Les fichiers Headers ont plusieurs particularités. Il s'agit avant tout de fichiers d'"entête" chargés de fournir des informations au compilateur pour qu'il sache où chercher les fonctions, et leur utilité dans le programme. Il permet aussi de rendre le code plus propre: nous pourrions faire nos headers directement dans notre .c, mais c'est plus moche, et la compilation d'un .h diffère de celle d'un .c (tentez cc *.h vous verrez bien). Un header, c'est donc un fichier de préparation à la compilation. Il contiendra ainsi les prototypes des fonctions utilisées dans notre programme. Vous pouvez trouver des exemples de headers dans les librairies que nous avions déjà utilisé! Souvenez-vous: Nous avions utilisé: #include <unistd.h> qui corresponds à inclure le fichier .h de la libraire unistd. les <> signifient que le header se trouve dans le dossier include de notre compilateur. Pour inclure un fichier local, il suffit de faire tout simplement! Donc revenons sur notre histoire de warnings, nous allons créer un .h pour la lib précédente que nous avons créé: #ifndef _MY_H_ #define _MY_H_ void my_putchar(char); void my_putstr(char *); #endif /* _MY_H_ */ Je vais vous expliquer le fichier lignes par lignes. Mais avant cela, je vais vous expliquer ce qu'est un define. Un define est une sorte de variable statique et constante. Elle permet de remplacer la valeur du define par la valeur associée à celui-ci. Voici un exemple simple: #define VERSION "1.0.0" J'ai définit VERSION comme ayant comme value 1.0.0 Je peux le ré-utiliser dans mon code, si j'inclus le fichier .h qui contient ce define, comme ceci: int main(void) { my_putstr(VERSION); return (0); } ATTENTION: il ne s'agit pas d'une variable. Un define est remplacé par le compilateur par la valeurqui lui est destinée! J'espère que vous m'aurez compris... Passons donc à la définition de notre fichier .h: #ifndef _MY_H_ Notre première ligne de code permet d'éviter ce qu'on appelle une "double inclusion", en effet, si on inclue notre fichier .h dans plusieurs autres fichiers du même programme, nous pouvons créer de multiples inclusions, ce qui ne sert à rien, et ralentit la compilation. #define _MY_H_ Si notre fichier n'a jamais été inclus, nous définissons qu'il l'a à présent été void my_putchar(char); void my_putstr(char *); On y ajoute ensuite les prototypes des fonctions utilisées... #endif /* _MY_H_ */ Enfin, on ferme notre "#ifndef" (if not defined). Nous y sommes, revoyons notre main à présent: #include "my.h" int main(void) { my_putstr("coucou\n"); return (0); } Compilons le: Et voilà! Plus aucun warnings ou erreurs! Nous pouvons passer à la suite! III- Les Structures. Une structure est un ensemble de données. Il permet de stocker plusieurs données sous un même typpage. (nous verrons en même temps la déclaration de typpages, grâce à typedef). Construction d'une structure: struct s_nom_de_ma_struct { int valeur_numerique; char valeur_caractere; typpage valeur_n'importe_quel_typpage; }; C'est aussi simple que cela. A savoir : Une structure doit être déclarée dans un .h!Nous allons créer une structure, qui contiendra une chaine de caractères "pseudo" et une autre chaine de caractère "texte": struct s_mastruct { char *pseudo; char *texte; }; Nous allons afficher les données de notre structure: void set_structure(struct s_mastruct *mastruct) { /* (*mastruct).pseudo = "AlexMog" est la même chose que mastruct->pseudo = "AlexMog" */ mastruct->pseudo = "AlexMog"; mastruct->texte = "Coucou! :)"; } int main(void) { struct s_mastruct mastruct; set_structure(&mastruct); my_putstr("Pseudo: "); my_putstr(mastruct.pseudo); my_putchar('\n'); my_putstr("Texte: "); my_putstr(mastruct.texte); my_putchar('\n'); return (0); } Ce code nous affichera: A SAVOIR: lorsque vous utilisez un pointeur sur structure (comme dans la fonction set_structure) les "." sont remplacés par "->". Voilà, vous savez à présent vous servir des structures. Mais vous avez remarqué que taper "struct s_mastruct mastruct" est tout de même long pour la ré-utilisation de cette structure... Nous allons donc créer notre propre typage! Rendez-vous dans le .h: struct s_mastruct { char *pseudo; char *texte; }; et créons notre nouveau typage: typedef struct s_mastruct { char *pseudo;char *texte; } t_mastruct; Nous pouvons à présent déclarer nos structures comme ceci: Cool n'est-ce pas ? Vous remarquerez, pour ceux qui font de la programmation orientée objet, qu'une structure ressemble énormément à un objet, il s'agit en faite de la maman de l'objet connu actuellement! Nous verrons cela plus en détails, lorsque j'aborderais les notions sur la programmation en C Modulaire dans un prochain cours (dans longtemps donc, puisque nous devons voir les pointeurs sur fonctions avant (un objet = une structure contenant un ensemble de données et de pointeurs sur fonctions allouée dans la mémoire)). Voilà! A très bientôt pour un prochain cours! Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr1 point
-
Et voila le deuxieme tutoriel où je vais vous expliquer tout le code du pathfinding ( et oui enfin ! ) Tout d'abord n'hésitez pas a télécharger les sources en bas du post afin de les lire en même temps, c'est plus pratique pour comprendre de quoi je parle. On va commencer par le prototype de la fonction : path_direction* create_path(const int largueur, const int hauteur, int map[][hauteur], const path_pos debut, const path_pos fin, int pivot) Cette fonction retourne un pointeur vers une structure, je vais vous expliquer a quoi elle sert vers la fin. Il faut donc en paramètre la largueur et la hauteur de la map (attention, la map doit être de format map[largueur][hauteur] et non, map[hauteur][largueur] la map qui contient des nombres afin de représenter votre terrain, et maintenant les trucs intéressant : la structure path_pos ne contient que deux int, x et y, pour connaître la position du début et celle de la fin. Attention, le début de la map commence a (0, 0), il faut faire attention ! Et enfin le pivot, mais qu'est ce que c'est ? C'est tout simplement tout les nombres qui sont supérieur ou égal a lui sont traversables, tout ceux inférieur sont des murs par exemples. cela nécessite par contre de penser a cela dès le début e la conception du jeu mais c'est pas très difficile. personnellement, j'utilise souvent des énumération pour définir les différentes tiles (blocs) de la map. ensuite : if(debut.x == fin.x && debut.y == fin.y) { return NULL; } assez explicite je crois, on retourne NULL afin de savoir qu'il n'y a pas de chemin. On doit créer ensuite une grille de coût , de la taille qui faut exactement, et on initialise le tout a 0, c'est très important ! on met a jour a grille de coût, en mettant a 1 le début. Ainsi, on sait que tout les blocs avec un coût égal a zéro sont non explorés Il faut ensuite créer une file, les positions actuelle et les suivantes, ce qui donne : path_pos actuel; path_pos suivant; control control_list; la structure control et donc se qui va nous servir a contrôler la file, on va mettre les donnée en file a partir de cette structure là. Elle contient un pointeur vers la première donnée, pour la récupérer. (n'hésitez pas a regarder le précédent tutoriel pour voir de quoi je veux parler) Et aussi un pointeur vers la dernière données, afin de mettre les données dans la file plus rapidement. S'il n'y en avait pas, on aurait du parcourir TOUTES les données de la file une par une afin de trouver la fin. Vous imaginez sur une énorme file de 1000 données ? Il faut initialiser la file avec la position de début et on commence les choses sérieuse. Il faut ensuite créer une boucle qui s’arrête quand on a trouvé la fin ou que la file est vide. dedans, on met a jour la position actuelle qui erre égale a la valeur du début de file. si la position actuelle est égale a celle de fin on sort de la boucle, sinon on regarde sur le coté. Cela donne en code: while(control_list.premier != NULL && fini) { actuel.x = control_list.premier->actuel.x; actuel.y = control_list.premier->actuel.y; if(actuel.x == fin.x && actuel.y == fin.y) { fini = 0; } if(actuel.x != 0) { if(map[actuel.x-1][actuel.y] >= pivot && poid[actuel.x-1][actuel.y] == 0) { suivant.x = actuel.x-1; suivant.y = actuel.y; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&control_list, suivant); } } if(actuel.x != largueur -1) { if(map[actuel.x+1][actuel.y] >= pivot && poid[actuel.x+1][actuel.y] == 0) { suivant.x = actuel.x+1; suivant.y = actuel.y; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&control_list, suivant); } } if(actuel.y != 0) { if(map[actuel.x][actuel.y-1] >= pivot && poid[actuel.x][actuel.y-1] == 0) { suivant.x = actuel.x; suivant.y = actuel.y-1; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&control_list, suivant); } } if(actuel.y != hauteur - 1) { if(map[actuel.x][actuel.y+1] >= pivot && poid[actuel.x][actuel.y+1] == 0) { suivant.x = actuel.x; suivant.y = actuel.y+1; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&control_list, suivant); } } remove_to_file(&control_list); } Il faut bien entendu éviter de partir sur les coté de la map, sinon on risque d'avoir des problèmes de mémoires. Vous vous dites aussi sûrement : "mais c'est quoi add_to_file et remove to file" non ? Ce sont les structure qui servent a mettre les données dans la file, ou a les enlever. (regardez dans le code source fournit, elle y sont au début.) A partir de là, la grille de coût est fini, on peut vider totalement la file, on n'en a plus besoin. ( il faut éviter les fuites mémoires) : while(control_list.premier != NULL) { remove_to_file(&control_list); } Et non ce n'est toujours pas fini : Il faut regarder la variables fini, qui si elle est égale a zéro, signifie qu'on a trouvé la fin ,sinon, il faut encore retourner NULL. si le chemin est trouvé, on se place sur la position de fin et regarde a coté. On va dans la direction on le coût est égal au coût - 1 de la case. Il ne faut surtout PAS prendre la case qui a un coût inférieur a celle autour, car a ce stade la, certaine case n'ont pas encore été explorer ( se n'était pas la peine, on avait trouver le plus court chemin jusqu’à la fin) et sont donc encore égale a 0. On risque alors de se trompé totalement de chemin. On met ensuite dans la pile les directions contraire ou on va aller. (on part de la fin je vous rappelle) et on retourne a la fin cette pile. En code : if (fini == 0) { fini = 1; actuel.x = fin.x; actuel.y = fin.y; path_direction *control = NULL; char direction; while((actuel.x != debut.x && fini) || (actuel.y != debut.y && fini)) { //les directions sont inversé car le png va aller dans l'autre sens if(poid[actuel.x][actuel.y+1] == poid[actuel.x][actuel.y] - 1) { direction = NORD; actuel.y++; } else if(poid[actuel.x][actuel.y-1] == poid[actuel.x][actuel.y] - 1) { direction = SUD; actuel.y--; } else if(poid[actuel.x+1][actuel.y] == poid[actuel.x][actuel.y] - 1) { direction = OUEST; actuel.x++; } else { direction = EST; actuel.x--; } empile(&control, direction); } return (control); } La structure path_direction comporte, une direction sous forme de point cardinaux (NORD, SUD...) et un pointeur vers la donnée suivante (c'est une pile je vous rappelle). la fonction empile sert a empiler la direction dans la pile (elle va tout au début). A la fin, on retourne la pile, qu'il faut récupérer avec un pointeur sur une structure path_direction Le seul problème de ce path_finding actuel, c'est qu'il faut éviter que le chemin, se trouve sur les bord, sinon on peut passer de l'autre coté de la map dans certain cas, ce qu'il faut a tout prix empêcher. Dans le cas de situation différentes a celle d'un labyrinthe, (quand les chemins ont une grande chance d'être droit, vous pouvez dirigez le path_finding en lui faisant allez dans la direction vers la fin et en transformant la file de départ en pile. Il faut alors pouvoir réécrire un coût d'une bloc si la deuxième fois, le coût est plus faible. Bref, il est facilement améliorable et il ne tiens qu'à vous de le récréer totalement. Et voila le tour est joué, vous avez maintenant un path_finding qui marche https://github.com/daemondragon/pathfinding.git1 point
-
ATTENTION: Ici, tu passe la map en COPIE! C'est pas du tout propre, et tu fais très très mal à ta stack (tu copie toute la map dans ta stack, donc, si tu as une map trop grande, PAFF! Segfault.) Envois plutot un int **map au lieu d'un int map[][haueur] .1 point
-
"Traduction" de my_putchar sur Windows : #include <Windows.h> ... void my_putchar(char c) { HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); WriteFile(hOutput, &c, 1, NULL, NULL); }1 point
-
Pendant que j'y suis, je recommande aussi http://bootswatch.com/ qui permet de visualiser des thèmes, des morceaux de codes et qui possède une API pas mal !1 point
-
1 point
