Author: Robin C.

Projets

Un Puissance 4 sur ta NumWorks !

Le Puissance 4 est probablement un jeu de votre enfance, c’est pourquoi je vous propose de jouer à ma version du Puissance 4 directement sur votre NumWorks avec un ami.

L’idée

L’idée du Puissance 4 a été longuement réfléchi car le projet de ces vacances était libre et j’avais eu l’idée de faire un jeu sur la NumWorks mais je ne savais pas lequel faire. Après avoir parcouru le site à la recherche de jeu original qui n’avait pas été déjà fait, l’idée du Puissance 4 m’est venu à l’esprit.

La réalisation

Pour réaliser le jeu j’ai avant tout fait en sorte qu’il soit jouable sur la console avant de faire la partie graphique de la calculatrice (même si certains ajouts ont été fait pendant le développement de la partie graphique).

Le Script

Je vais maintenant vous présenter le script et vous faire une brève explication de chacune des fonctions :

from kandinsky import fill_rect as rect, draw_string as txt
from time import sleep
from ion import keydown

Au tout début du script nous avons évidemment les appels des différents modules :

  • Kandinsky : c’est un des modules propriétaire de NumWorks qui est utilisé afin de dessiner des rectangles ou même écrire du texte sur l’écran de la calculatrice
  • Time : permet avec la fonction sleep que j’appel de mettre des pause dans le script
  • Ion : c’est le second module propriétaire de NumWorks qui permet de prendre en compte l’appui des touches pendant le script.

Nous avons ensuite la définition des variables globales :

# 1 = rouge // 2 = jaune
# Variables globales
player = 1 #Définit le joueur qui doit jouer
grille_preview = [0, 0, 0, 0, 0, 0, 0] #Est utilisé pour déterminer les positions possible du preview
grille = [[0 for i in range(7)] for i in range(6)] #La matrice qui représente la grille de jeu

#Les couleurs utilisées
rouge = (182, 2, 5)
jaune = (255, 181, 49)
gris = (191, 189, 193)

pos = 3 #Donne la position du preview

#Les points des joueurs
points_rouge = 0
points_jaune = 0

Ensuite une des fonctions majeures du jeu : la fonction de vérification. Cette fonction va après chaque coup vérifier toutes les positions afin de voir si il y a un gagnant ou pas.

def verifie(): #Gagnant ?
  for i in range(6): #lignes
    for j in range(4):
      if grille[i][j] == player and grille[i][j+1] == player and grille[i][j+2] == player and grille[i][j+3] == player:
        gagnant(player)
  for i in range(3): #colonnes
    for j in range(7):
      if grille[i][j] == player and grille[i+1][j] == player and grille[i+2][j] == player and grille[i+3][j] == player:
        gagnant(player)
  for i in range(3): #diagonales
    for j in range(4):
      if grille[i][j] == player and grille[i+1][j+1] == player and grille[i+2][j+2] == player and grille[i+3][j+3] == player:
        gagnant(player)
  for i in range(3, 6):
    for j in range(4):
      if grille[i][j] == player and grille[i-1][j+1] == player and grille[i-2][j+2] == player and grille[i-3][j+3] == player:
        gagnant(player)

Cependant je n’ai pas tout dit à propos de cette fonction car celle ci n’est pas tout à fait de moi : en effet avant d’avoir cette fonction là j’avais codé une fonction vérification mais celle ci faisait environ 70 lignes et n’était pas du tout optimisé ce qui amenait à des ralentissement, ChatGPT m’a donc aidé à réduire la fonction afin d’avoir la version ci-dessus. Et donc voici en exclusivité ma fonction de vérification originelle :

def verifie():
    #horizontalement
    for i in range(6):
        for j in range(4):
            rouge = 0
            jaune = 0
            for k in range(4):
                if grille[i][j+k] == 1 :
                    rouge += 1
                elif grille[i][j+k] == 2 :
                    jaune += 1
            if rouge == 4 :
                player_won(1)
            elif jaune == 4 :
                player_won(2)
    
    #verticalement
    for i in range(3):
        for j in range(7):
            rouge = 0
            jaune = 0
            for k in range(4):
                if grille[i+k][j] == 1 :
                    rouge += 1
                elif grille[i+k][j] == 2 :
                    jaune += 1
            if rouge == 4 :
                player_won(1)
            elif jaune == 4 :
                player_won(2)

    #diagonalement
    """(ij)
    /
    2 diag de 4 : 03 12 21 30 // 26 35 44 53
    2 diag de 5 : 04 13 22 31 40 // 16 25 34 43 52
    2 diag de 6 : 05 14 23 32 41 50 // 06 15 24 33 42 51
    
    \
    2 diag de 4 : 03 14 25 36 // 20 31 42 53
    2 diag de 5 : 02 13 24 35 46 // 10 21 32 43 54
    2 diag de 6 : 00 11 22 33 44 55 // 01 12 23 34 45 56
    """

    #création des listes pour vérifier
    diag4 = [[[0, 3], [1, 2], [2, 1], [3, 0]], [[2, 6], [3, 5], [4, 4], [5, 3]], [[0,3], [1,4], [2,5], [3,6]], [[2,0], [3,1], [4,2], [5,3]]]
    diag5 = [[[0, 4], [1, 3], [2, 2], [3, 1], [4, 0]], [[1, 6], [2, 5], [3, 4], [4, 3], [5, 2]], [[0, 2], [1, 3], [2, 4], [3, 5], [4, 6]], [[1, 0], [2, 1], [3, 2], [4, 3], [5, 4]]]
    diag6 = [[[0, 5], [1, 4], [2, 3], [3, 2], [4, 1], [5,0]],[[0, 6], [1, 5], [2, 4], [3, 3], [4, 2], [5,1]],[[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5,5]],[[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5,6]]]

    #vérification des diagonales de 4
    for i in range(4):
        if grille[diag4[i][0][0]][diag4[i][0][1]] == grille[diag4[i][1][0]][diag4[i][1][1]] == grille[diag4[i][2][0]][diag4[i][2][1]] == grille[diag4[i][3][0]][diag4[i][3][1]] :
            if grille[diag4[i][0][0]][diag4[i][0][1]] == 1 :
                player_won(1)
            elif grille[diag4[i][0][0]][diag4[i][0][1]] == 2 :
                player_won(2)

    #vérification des diagonales de 5
    for i in range(4):
        for j in range(2):
            if grille[diag5[i][0+j][0]][diag5[i][0+j][1]] == grille[diag5[i][1+j][0]][diag5[i][1+j][1]] == grille[diag5[i][2+j][0]][diag5[i][2+j][1]] == grille[diag5[i][3+j][0]][diag5[i][3+j][1]] :
                if grille[diag5[i][0+j][0]][diag5[i][0+j][1]] == 1 :
                    player_won(1)
                elif grille[diag5[i][0+j][0]][diag5[i][0+j][1]] == 2 :
                    player_won(2)

    #vérification des diagonales de 6               
    for i in range(4):
        for j in range(3):
            if grille[diag6[i][0+j][0]][diag6[i][0+j][1]] == grille[diag6[i][1+j][0]][diag6[i][1+j][1]] == grille[diag6[i][2+j][0]][diag6[i][2+j][1]] == grille[diag6[i][3+j][0]][diag6[i][3+j][1]] :
                if grille[diag6[i][0+j][0]][diag6[i][0+j][1]] == 1 :
                    player_won(1)
                elif grille[diag6[i][0+j][0]][diag6[i][0+j][1]] == 2 :
                    player_won(2)

Ma fonction donc vérifiait chaque possibilité afin de gagner au jeu mais le plus long était surtout les diagonales qui n’étaient pas automatisées avec des boucles sans variables définies mais plutôt avec des listes interminables des positions possibles des diagonales et cela ralentissait considérablement le script. C’est pour cela que j’ai préféré utilisé la fonction de ChatGPT.

Par la suite nous avons une autre fonction majeure qui est celle qui est appelée dans le cas d’une fin de partie donc soit ci un joueur a gagné ou si il y a égalité et c’est cette même fonction qui redémarre une partie donc rénitialise la grille et actualise les scores :

def gagnant(winner): #Met fin à une partie gagnant ou pas
  global points_jaune, points_rouge, player, nb_partie, grille, partie
  affichage_grille()
  if winner == 1 : #Vérifie la variable winner pour savoir qui a gagné et agir en conséquence
    points_rouge += 1
    player = 2
    txt("Rouge a gagné !", 88, 20)
  elif winner == 2 :
    points_jaune += 1
    player = 1
    txt("Jaune a gagné !", 88,20)
  else :
    txt("C'est une égalité", 76, 20)
  wait() #La fonction attend qu'il y ai une touche de pressé (permet de voir la grille avant sa rénitialisation
  actu_src() #Actualisation des score
  grille = [[0 for i in range(7)] for i in range(6)] #Rénitialise la grille
  affichage_grille() #Affiche la grille

Ensuite nous avons la fonction selection qui est je dirai la dernière fonction majeure du script, elle permet au joueur de selectionner la colonne ou il souhaite ajouter son jeton et appel la fonction jouer que nous allons voir juste après :

def selection():
  global pos
  affichage_grille()
  preview(pos) #Affiche le preview du jeton (par défaut la 4ème colonne)
  add = 1
  while True : # Boucle qui permet de prendre en compte l'appui des touches et agit en conséquence.
    preview(pos)
    while colonne_pleine(pos):
      pos = (pos+add)%7
      preview(pos)
    key_pressed = wait() #Récupère la touche appuyé
    if key_pressed == 0: #Flèche de gauche // décale le preview vers la gauche
      add = -1
    if key_pressed == 3:#Flèche de droite // décale le preview vers la droite
      add = +1
    if key_pressed==0 or key_pressed==3: #Calcul la position du preview 
      pos = (pos+add)%7
      preview(pos)
    if key_pressed == 4 or key_pressed == 52 : #OK ou EXE (permet de jouer le coup)
      rect(75, 17, 170, 20, (255,255,255))
      jouer(pos)

Suite à cela il y a la fonction jouer qui est appelé dans la fonction selection et qui permet de jouer le coup dans la colonne sélectionné dans selection() :

def jouer(colonne): # Ajoute un jeton dans la colonne donnée
  global player
  if player == 1 : #Si c'est au tour de rouge
    animation(colonne) # Fais l'animation de chute du jeton
    grille[gravite(colonne)][colonne] = 1 #Modifie la matrice 
    verifie() #Vérifie si il y a un gagant
    player = 2 #Change de joueur
  elif player == 2 : #La même chose que pour le rouge mais pour le jaune
    animation(colonne)
    grille[gravite(colonne)][colonne] = 2
    verifie()
    player = 1
  grille_pleine() #Vérifie si la grille est pleine dans le cas d'un nul

Après il y a la fonction qui anime la chute du jeton dans la grille :

def animation(colonne): #Animation chute
  if player == 1 : #Définit la couleur du jeton
    color = rouge
  else :
    color = jaune
  for i in range(0, gravite(colonne)+1): #Dessine des jeton à la suite jursqu'à la dernière ligne
      ligne = (i-1)*(i!=0)
      rect(75+(25*colonne),42+(ligne*25),20,20,gris)
      sleep(0.05)
      draw_cercle(75 + (25*colonne) + 7, 42 + (i*25) + 2, color)
      sleep(0.05)

Ensuite la fonction qui dessine les cercles mais qui n’est pas de moi mais de M.Robert :

def draw_cercle(x,y,color): #Fait des cercles (Par VR)
  for d in range(6):
    rect(x-d+(d==0),y+d+(d==5),6+2*d-2*(d==0),16-2*d-2*(d==5), color)

Par la suite il y a ma fonction colonne_pleine qui dit si la colonne donnée en paramètre est pleine ou pas :

def colonne_pleine(colonne):
  if (grille[0][colonne] == 1) or (grille[0][colonne] == 2):
    return True
  return False

Une fonction similaire à la précedente : fonction grille_pleine utilise colonne_pleine afin de déterminer si la grille est pleine ou pas donc si il y a égalité :

def grille_pleine(): #Vérifie si il y a une égalité soit si la grille est pleine
  colonne_pleines = 0
  for i in range(7): #Passe en revue les premières lignes de chaque colonne
    if colonne_pleine(i):
      colonne_pleines += 1
  if colonne_pleines == 7: #Si toutes les colonnes sont pleine
    gagnant(0) #Appelle la fonction gagnant pour mettre fin à la partie

Il y a aussi la fonction gravité qui va retourner la ligne la plus basse où le jeton peut aller :

def gravite(colonne): #Détermine la ligne où le jeton peut se placer
  ligne = 5
  while grille[ligne][colonne] != 0: #parcours la colonne de haut en bas jusqu'à trouver la ligne vide la plus basse 
    if ligne == 0 :
      return ligne
    ligne -= 1
  return ligne

Une autre des fonctions principales : affichage_grille permet comme son nom l’indique d’afficher la grille entière :

def affichage_grille():
  rect(75, 42, 175, 150, (255,255,255))
  pos_x, pos_y_base, marge = 50, 42, 25
  for i in range(7):
    pos_x += marge
    pos_y = pos_y_base
    for y in range(6):
      cote = 20
      if grille[y][i] == 1:
        color = rouge
      elif grille[y][i] == 2:
        color = jaune
      else :
        color = gris
      if grille[y][i] == 1 or grille[y][i] == 2:
        rect(pos_x, pos_y, cote, cote, gris)
        draw_cercle(pos_x + 7, pos_y + 2,color)
      else:
        rect(pos_x, pos_y, cote, cote, gris)
      pos_y += marge

La fonction efface une possible grille avec un rectange blanc de la même taille que la grille puis réaffiche la grille

Voici ce que produit la fonction :

Ensuite il y a affichage_preview qui va afficher le preview du jeton au bon endroit :

def affichage_preview(col_preview):
   rect(75, 17, 170, 20, (255,255,255)) #Efface l'ancien preview
   if player == 1 : #Choisi la bonne couleur
      color = rouge
   else :
      color = jaune
   draw_cercle(75 + (col_preview * 25) + 7, 17+2, color) #Fait le preview au bon endroit

Il y a la fonction wait qui retourne la touche sur laquelle vous appuyez :

def wait(buttons=(0,1,2,3,4,52)): #Retourne la touche appuyée
   while True:
      for i in buttons:
         if keydown(i):
            while keydown(i): True
            return i

Et enfin les deux dernières fonctions qui sont liées : les fonctions du score, il y a la fonction affichage_src qui est appelé au début du jeu afin d’afficher le score :

#Score par Thomas S. mais code par Robin C.
def affichage_src():
   txt("J-1", 22, 42)
   draw_cercle(35,70,rouge)
   txt("Score", 12, 117)
   if points_rouge < 10 :
      largeur = 32
   else :
      largeur = 27
   txt(str(points_rouge),32,142)
   txt("J-2", 267, 42)
   draw_cercle(280,70,jaune)
   txt("Score", 257, 117)
   if points_jaune < 10 :
      largeur = 277
   else :
      largeur = 272
   txt(str(points_jaune),277,142)

def actu_src(): #Actualise le score
   txt(str(points_rouge),37-5*len(str(points_rouge)),142)
   txt(str(points_jaune),282-5*len(str(points_jaune)),142)

Et il y a aussi la fonction actu_src qui va à chaque fin de partie, actualiser le score en écrasant l’ancien score.

Voici ce que produit la fonction affichage_src() seule :

Et pour finir il y a le lancement du jeu à la fin avec juste avant le code qui permet d’afficher le lien en bas de l’écran :

#Lien article
rect(0,200,320,22,(148,113,222))
txt("Code by nsi.xyz/puissance4",33,202,(242,)*3,(148,113,222))

#lancement du jeu
affichage_src()
selection()

Images du jeu

Conclusion

Pour conclure le tout, ce projet a été très plaisant à faire et très instructif. Il faut savoir que faire un jeu sur la NumWorks comme le mien demande du travail notamment sur la prise en main de la partie graphique qui n’a pas été sans problèmes pour moi mais avec les entrainements de M.Robert sur twitter la prise en main fut plus simple.

Lien du jeu

Il existe deux liens pour le jeu, sachez que seul le premier garanti de disposer de la dernière version et que le deuxième est un lien alternatif qui peut être dépassé.

NumApps

Puissance 4 en python, NumWorks

Le Puissance 4 est un jeu de société qui se joue à deux. Le principe est d’aligner 4 jetons que ça soit horizontalement, verticalement ou en diagonale.

Captures d’écran

Commandes

◁ et ▷OK ou Exe
Choisir la colonneValider le coup

À propos

Vous pouvez en savoir plus sur le jeu en lisant l’article qui détaille le programme en lui même, un projet réalisé dans le cadre de la spécialité NSI.

Lien du jeu

Il existe deux liens pour le jeu, sachez que seul le premier garanti de disposer de la dernière version et que le deuxième est un lien alternatif qui peut être dépassé.

Tutoriels

Comment héberger un serveur Minecraft sur son ordinateur ?

N’avez vous jamais rêvé de pouvoir avoir un serveur Minecraft pour pouvoir jouer avec vos amis autre que sur un serveur public ? Avec ce tutoriel vous apprendrez comment en héberger un sur votre ordinateur et comment le configurer. 

Prérequis

Tableau des exigences pour un serveur minecraft (pris sur le fandom)

Télécharger le serveur

La première chose à faire est de télécharger le fichier .jar du serveur. Pour cela rendez-vous sur le site : https://mcversions.net/

Puis téléchargez le fichier de la version que vous voulez pour votre serveur.

Prenons par exemple un serveur en 1.16.2 :

Je recherche la version 1.16.2 dans la barre de recherche et deux choix s’offrent à moi : soit télécharger une version stable ou une version snapshot (instable). Je vais choisir la version stable pour éviter de futurs problèmes de crash, bugs ou autres.

Une fois que j’ai cliqué sur Download j’arrive sur cette page : 

Sur la page je vais cliquer sur “Download Server Jar” pour récupérer le .jar du serveur.

Après l’avoir téléchargé faites un dossier sur votre ordinateur (peu importe sa localisation) puis placez le .jar dedans. Exécutez le, des fichiers vont apparaître.

Avant :

Après :

Vous allez maintenant ouvrir le eula.txt et changer le eula=false en eula=true. Accepter le EULA fait que vous acceptez le Contrat de Licence Utilisateur Final de Minecraft.

Après ça sauvegardez le fichier et relancez le server.jar

Le serveur va désormais se lancer quand vous exécuterez le fichier.

Pour éteindre le serveur tapez stop dans la console et après quelques instants il devrait se fermer.

De nouveaux fichiers sont apparus !

Passons en revue ces derniers : 

  • logs : vous trouverez des fichiers .txt avec la totalité de la console écrite dedans. Un nouveau fichier se crée lors de la fermeture du serveur.
  • world : la map de votre serveur, vous pouvez glisser un de vos monde à l’intérieur pour charger celui-ci.
  • banned-ips/players des fichiers texte ou vous pourrez retrouver la liste des personnes bannis sur le serveur.
  • ops : un fichier texte ou vous trouverez toutes les personnes avec les permissions administrateur.
  • usercache : un fichier texte qui liste toutes les personnes qui se sont connecté au moins une fois sur le serveur.
  • whitelist : un fichier texte ou vous pouvez mettre des gens en liste blanche si vous voulez que le serveur ne soit accessible que pour les personnes répertorié dans le fichier.
  • server.properties : le fichier texte de configuration du serveur.

Configuration

Pour configurer le serveur vous devez ouvrir le server.properties

Voici une liste des paramètres de base qui peuvent être intéressant : 

spawn-protection=16 	// Définit une zone de protection autour du point d'apparition.
force-gamemode=false 	// Force le changement de mode de jeu pour celui par défaut pour les joueurs qui se connectent.
allow-nether=true 	// Active ou non le Nether
gamemode=survival 	// Définit le mode de jeu par défaut
difficulty=easy 	// Définit la difficulté par défaut
spawn-monsters=true 	// Active ou non l'apparition des monstres
pvp=true 	// Active ou non les dégâts entre joueurs
level-type=default 	// Définit le type de monde pour la génération
hardcore=false 	// Active ou non le mode Hardcore
enable-command-block=false 	// Active ou non les blocs de commandes
max-players=20 	// Définit la limite de joueurs sur le serveurs
spawn-npcs=true 	// Active ou non l'apparition des Villageois
allow-flight=false 	// Autorise ou pas le vol (ne permet pas aux joueurs de voler mais autorise seulement le vol)
level-name=world 	// Définit le nom du dossier ou le monde se trouve (permet notamment de changer de monde)
view-distance=10 	// Définit la distance de rendu maximal sur le serveur
resource-pack= 	// Active un pack de ressource pour le serveur (les joueurs auront le choix ou pas de l'activer)
spawn-animals=true 	// Active ou non l'apparition des animaux
white-list=false 	// Active ou non une liste blanche pour le serveur (mettre le nom des joueurs dans le whitelist.json)
generate-structures=true 	// Active la génération des structures ou pas lors de la génération du monde
max-build-height=256 	// Définit la hauteur de construction maximale
online-mode=true 	// IMPORTANT : Si activé les joueurs n'ayant pas acheté le jeu (minecraft cracké) ne pourront pas rejoindre et seuls les joueurs ayant acheté le jeu le pourront, cependant si désactivé les skins des joueurs sera le skin d'Alex soit le skin de base
level-seed= 	// Définit la seed du monde pour la génération
motd=A Minecraft Server 	// Définit ce que le serveur affichera dans le menu multijoueurs (Utilisez ce site pour le modifier plus facilement https://minecraft.tools/fr/motd.php)

Si vous voulez en savoir plus sur le server.properties n’hésitez pas à visiter ce site : https://minecraft.fandom.com/wiki/Server.properties

Après avoir configuré votre serveur il va vous falloir faire une dernière chose afin de pouvoir utiliser le serveur correctement :

Vous allez maintenant ouvrir un fichier texte et à l’intérieur vous allez placer cette ligne de code :

java -Xmx4096M -Xms4096M -jar forge-1.16.2-33.0.61.jar

Après cela, enregistrez le fichier en .bat avec le nom que vous souhaitez.

Le code est assez simple : -Xmx4096M -Xms4096M désigne la quantité de RAM que vous allouerez au serveur (veuillez si vous voulez changer de valeur mettre une puissance de 2 : 1024, 2048, 3072, 4096 …)

ensuite le forge-1.16.2-33.0.61.jar désigne le fichier du serveur qui va s’ouvrir, il est donc à modifier afin de correspondre au nom du fichier de votre serveur

Vous pouvez aussi rajouter le paramètre nogui à la fin de la ligne si vous ne souhaitez pas cet interface et que vous ne voulez avoir qu’un interpréteur de commande :

Une fois ceci fait votre serveur est configuré et est prêt à être utilisé pour jouer à minecraft dans sa version vanilla (sans mods) et à partir de maintenant il va falloir permettre à vos amis de vous rejoindre, et une des solutions est d’utiliser le logiciel Hamachi. Voici une vidéo permettant d’utiliser Hamachi pour vous connecter vous et vos amis sur le serveur :

https://youtu.be/f3L_g2phhyI

Important

Pour se connecter au serveur si il est hébergé sur votre ordinateur l’ip du serveur sera : localhost alors que vos amis devront regarder sur Hamachi l’adresse ip de l’odinateur qui héberge le serveur et la copier afin d’avoir ce modèle : xx.xx.xx.xx:port sachant que le port par défaut est 25565 si il n’est pas modifié dans le server.properties

adresse ip de mon ordinateur sur Hamachi. l’adresse Ip de mon serveur serait 25.47.160.63:25565

Et la première fois que vous vous connecterez n’oubliez pas dans la console du serveur de faire la commande : op 'Votre pseudo' afin de vous ajouter les permissions administrateur

Maintenant vous avez un serveur que vous pouvez utiliser avec vos amis mais le tutoriel ne s’arrête pas là sauf si votre serveur vous plaît comme il est et que vous ne voulez pas ajouter de mods

Avoir un serveur avec des mods

Après vous avoir montré comment héberger un serveur dit Vanilla je vais vous montrer comment avoir un serveur avec des mods grâce à Forge. Forge est une API qui permet à Minecraft de rajouter du contenu (mods).

Le serveur Forge est fortement similaire au serveur Vanilla (à par les mods) donc vous devrez probablement retourner sur les explications du serveur Vanilla pour le serveur Forge

Télécharger le serveur

Pour télécharger le serveur rendez vous sur ce site : https://files.minecraftforge.net/net/minecraftforge/forge/

Dans la partie de gauche, choisissez la version que vous voulez pour votre serveur (et accessoirement votre jeu) :

Enfin télécharger la dernière version du serveur en cliquant sur Installer :

Lorsque vous cliquerez sur Installer vous arriverez sur un site où vous aurez une pub, après quelques secondes cliquez sur SKIP en haut à droite et après cela le téléchargement se lancera.

Une fois que vous aurez téléchargé le .jar lancez le :

Enfin cliquez sur Install server et choisissez le dossier où vous souhaitez votre serveur enfin faites OK et patientez pendant que le serveur se télécharge

Après cela n’oubliez pas d’installer la version forge sur votre jeu : Install client, OK

Après que tout soit installé votre dossier de serveur devrait ressembler à cela :

comme pour le serveur Vanilla il vous faut exécuter le forge-1.xx.x.jar (et non pas le minecraft_server.1.xx.x.jar)

Ensuite acceptez le eula comme pour le serveur Vanilla et relancer le .jar

Le serveur est maintenant prêt il ne manque plus qu’à mettre les mods dans le dossier mods et pour la configuration, le serveur se configure comme la version Vanilla la seule différence peut venir du level-type si vous utilisez un mod qui modifie la génération du monde (Biomes O’ Plenty par exemple où il faut mettre biomesoplenty à la place de default dans le server.properties)

Et pour rejoindre le serveur n’oubliez pas de mettre aussi les mods présent sur le serveur dans votre jeu car sinon vous ne pourrez pas le rejoindre ce qui est dommage…

Le serveur est finalement fini et vous pouvez jouer avec vos amis dessus.

Art

Perspective : un paysage Synthwave

Dans le cadre de la 5ème édition du dispositif “Regards de Géomètre”, nous avons décidé dans le thème « Perspective » de produire un paysage synthwave.

Vidéo du projet

Origines de la Synthwave

Avant tout la synthwave est un genre musical électronique ayant émergé dans les années 2000/2010 qui s’inspire d’éléments des années 80. Et c’est justement dans les clips de ces musiques que l’on va retrouver ce type d’image.

Pour en savoir plus nous vous conseillons cette vidéo qui explique brièvement les origines.

Le Projet

Revenons donc au projet. Pour ce projet nous avons donc décidé de produire une image d’un paysage synthwave. Pour cela nous utilisons le module turtle ainsi que le module random, le module turtle est utilisé pour produire l’image est le module random est utilisé pour les étoiles de l’image où la taille et leur position est générée aléatoirement nous avons également utilisé le script permettant d’exporter une image générée par turtle en .png que vous pouvez retrouver ici.

Structure du script

Pour la structure du script nous avons décidé de découper chaque partie de l’image (pavage, fond, étoiles, soleil, ville et montagnes) afin de créer des fonctions et à la fin nous les avons toutes appelées dans un ordre précis pour que les différentes parties de l’image soit dans leur plan respectif.

Analyse du script

Nous allons donc analyser le script.

Commençons par l’appel des modules et la mise en place de turtle.

from turtle import *
from random import randint
# vérification des modules importés
try:
    from PIL import Image
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False
titre = "Perspective - Un paysage Synthwave"
title(titre+" | Au lycée, la meilleure spécialité, c'est la spé NSI")
setup(1280, 720) # définit la taille de la fenêtre
colormode(255) # permet l'utilisation de couleurs rgb
speed(0) #Remplaçable par tracer(2) (10x plus rapide) mais si il est utilisé des lignes du pavage peuvent manquer
hideturtle() #dissimule la tortue

On appelle les fonctions turtle, random avec pour random uniquement randint et on utilise une partie du script « exporter une image générée par turtle » pour vérifier que l’utilisateur a bien installé le module PIL et dans le cas contraire un message d’erreur s’affichera et lui donnera un lien pour installer le module et tout ça sans que le script ne s’arrête. Après la vérification on met en place le titre de la fenêtre qui va affiché le rendu ainsi que sa taille. Enfin on définit le type de couleurs utilisées (R,G,B), la vitesse de la tortue, et on dissimule la tortue (c’est plus joli).

Commençons par la première fonction : le fond

def fond():
    penup()
    rciel = 0
    gciel = 0 
    bciel = 0
    hauteur = -360
    goto(-642,-358)
    pendown()
    while hauteur != 360:
        pencolor(round(239 + rciel), round(41 + gciel), round(209 + bciel))
        forward(1280)
        hauteur += 1
        goto(-640, hauteur)
        rciel += (-29/180)
        gciel += (2/45)
        bciel += (7/720)

Pour le fond on aurait pu utiliser une fonction qui crée un rectangle et qui le remplit avec fill_rect, cependant la couleur dans ce cas est uni ce qui ne nous intéresse pas. Nous avons donc produit un script qui fait un fond dégradé qui fait avancer la tortue sur une ligne d’un pixel de large et à la fin de cette ligne la tortue est envoyé grâce à un goto à la ligne d’après et qui ajoute la différence de chaque couleur (rouge,vert et bleu) entre la couleur de début du dégradé et la couleur de fin. Tout ceci est arrondi car turtle n’est pas compatible avec des arguments à virgule (pour la fonction pencolor en tout cas).

Par la suite la fonction qui produit les étoiles a été codée :

def etoile():
    for i in range(90):
        penup()
        goto(randint(-720,720), randint(0,360))
        pendown()
        pencolor(255, 255, 255)
        lcercle = randint(1,3)
        fillcolor('white')
        begin_fill()
        circle(lcercle)
        end_fill()

Pour les étoiles on définit aléatoirement leur position sur la moitié haute de l’image, on les met en blanc, on définit aussi aléatoirement la taille de l’étoile et on créer l’étoile avec sa position, et sa taille en aléatoire puis on refait ce processus 90 fois pour avoir 90 étoiles.

Ensuite nous avons le soleil (Le script affiché n’est qu’une petite partie du script total du soleil car il est très long et qu’il se répète, il est donc inutile de commenter la suite) :

def soleil():
    penup()
    liste1 = [10,7,5,4,3,3,3,3,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,1,2,1,1,1]
    liste2 = [1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0]
    pliste1 = 0
    pliste2 = 0
    rsoleil = 0
    gsoleil = 0
    bsoleil = 0
    lsoleil = 8
    hauteur = 30
    goto(0,30)
    pendown()
    for i in range(15):
        pencolor(round(255 + rsoleil), round(23 + gsoleil), round(226 + bsoleil))
        forward(lsoleil)
        backward(2*lsoleil)
        hauteur += 1
        lsoleil += liste1[pliste1]
        pliste1 += 1
        goto(0, hauteur)
        rsoleil += (0)
        gsoleil += (114/101)
        bsoleil += (-203/202)
    forward(lsoleil)
    backward(2*lsoleil)
    penup()

Pour le soleil nous réutilisons le script du dégradé, cependant nous l’avons modifier pour que le point d’origine de la tortue soit au centre du rectangle et que la longueur de chaque ligne soit défini par une liste (ce qui permet de faire un cercle en prenant les longueur d’un cercle utilisable en pixel art). Pour ce qui est des endroits ou le soleil est coupé la tortue fait le tracé mais on a utilisé la fonction penup() qui fait que la tortue ne dessine plus.

Après nous avons la fonctions des montagnes (Encore une fois le script n’est pas complet car il se répète encore 3 fois après.) :

def montagne():
    #montagne derrière la première
    penup()
    goto(-480,0)
    fillcolor(110, 27, 188)
    begin_fill()
    for i in range(3):
        forward(250)
        left(120)
    end_fill()
    
    goto(-480,0)
    pencolor(51, 210, 246)
    ymontagne = 10
    for i in range(11):
        pendown()
        goto(-355,ymontagne)
        goto(-230,0)
        penup()
        goto(-480,0)
        ymontagne += 20

Pour le script des montagnes nous avons utilisé le script pour faire des triangles équilatéraux retrouvable ici. Et ensuite nous avons utilisé un ‘for i in range’ pour faire des goto enchaîné pour faire les lignes des montagnes.

Ensuite nous avons les fonctions de la ville. Pourquoi les fonctions car il y a une fonction pour chaque bâtiment différent ainsi qu’une fonction finale qui définit l’ordre des bâtiments.

def bat1():
    penup()
    rbat = 0
    gbat = 0 
    bbat = 0
    hauteur = 0
    pendown()
    xturtle, yturtle = pos()
    while hauteur != 72:
        pencolor(round(125 + rbat), round(35 + gbat), round(216 + bbat))
        forward(42)
        hauteur += 1
        goto(xturtle, hauteur)
        rbat += (-5/3)
        gbat += (-7/15)
        bbat += (-72/25)
    forward(42)
    penup()
    right(90)
    forward(72)
    left(90)

Pour le bâtiment 1 il y a un dégradé (toujours le même script) puis on fait que la tortue finisse le bâtiment en bas à droite de ce dernier pour pouvoir enchainer les bâtiments.

fun fact : Au début nous n’avions pas prévu les quelques lignes à la fin pour que la tortue puisse enchaîner les bâtiments sans que les fonctions des bâtiments aient besoin d’être modifiés ce qui nous a amené à avoir tous les bâtiments qui se chevauchaient.

def ville():
    penup()
    goto(-320,0)
    bat3(), bat2(), bat1(), bat4() ,bat3(), bat4(), bat3(), bat2(), bat1(), bat2(), bat1(), bat3(), bat1(), bat4(), bat2(), bat1(), bat3(), bat1(), bat4(), bat3()

Et à la fin on a fait la fonction ville qui appelle dans l’ordre choisi les bâtiments. Le goto permet de définir où commence le premier bâtiment, les autres se mettent juste après le premier sans se chevaucher ni laisser un espace.

Par la suite nous avons le pavage (très long aussi, il sera donc coupé) :

def pavage():
    colormode(255)
    pensize(5)
    speed(0)
    rciel = 0
    gciel = 0 
    bciel = 0
    hauteur = -360
    penup()
    goto(-640,-360)
    pendown()
    while hauteur != 0:
        pencolor(round(15 + rciel), round(4 + gciel), round(76 + bciel))
        forward(1280)
        hauteur += 1
        goto(-640, hauteur)
        rciel += (91/180)
        gciel += (1/36)
        bciel += (7/18)

Pour le début du pavage on retrouve encore le script du dégradé mais avec les couleurs modifiées.

pencolor(229, 123, 240)
    #Lignes au dessus du pavage
    pensize(4),penup(),goto(-640,0),pendown(),goto(640,0),pensize(2),penup(),goto(-640, 0),pendown()
    #lignes gauche
    penup(),goto(-20.00,0),pendown(),goto(-60.00,-360.00),penup(),goto(-60.00,0),pendown(),goto(-180.00,-360.00),penup(),goto(-100.00,0),pendown(),goto(-300.00,-360.00),penup(),goto(-140.00,0),pendown(),goto(-420.00,-360.00),penup(),goto(-180.00,0),pendown(),goto(-540.00,-360.00),penup(),goto(-220.00,0),pendown(),goto(-660.00,-360.00),penup(),goto(-260.00,0),pendown(),goto(-780.00,-360.00),penup(),goto(-300.00,0),pendown(),goto(-900.00,-360.00),penup(),goto(-340.00,0),pendown(),goto(-1020.00,-360.00),penup(),goto(-380.00,0),pendown(),goto(-1140.00,-360.00),penup(),goto(-420.00,0),pendown(),goto(-1260.00,-360.00),penup(),goto(-460.00,0),pendown(),goto(-1380.00,-360.00),penup(),goto(-500.00,0),pendown(),goto(-1500.00,-360.00),penup(),goto(-540.00,0),pendown(),goto(-1620.00,-360.00),penup(),goto(-580.00,0),pendown(),goto(-1740.00,-360.00),penup(),goto(-620.00,0),pendown(),goto(-1760.00,-360.00)
    #lignes droites
    penup(),goto(20,0),pendown(),goto(60.00,-360.00),penup(),goto(60.00,0),pendown(),goto(180.00,-360.00),penup(),goto(100.00,0),pendown(),goto(300.00,-360.00),penup(),goto(140.00,0),pendown(),goto(420.00,-360.00),penup(),goto(180.00,0),pendown(),goto(540.00,-360.00),penup(),goto(220.00,0),pendown(),goto(660.00,-360.00),penup(),goto(260.00,0),pendown(),goto(780.00,-360.00),penup(),goto(300.00,0),pendown(),goto(900.00,-360.00),penup(),goto(340.00,0),pendown(),goto(1020.00,-360.00),penup(),goto(380.00,0),pendown(),goto(1140.00,-360.00),penup(),goto(420.00,0),pendown(),goto(1260.00,-360.00),penup(),goto(460.00,0),pendown(),goto(1380.00,-360.00),penup(),goto(500.00,0),pendown(),goto(1500.00,-360.00),penup(),goto(540.00,0),pendown(),goto(1620.00,-360.00),penup(),goto(580.00,0),pendown(),goto(1740.00,-360.00),penup(),goto(620.00,0),pendown(),goto(1760.00,-360.00)
    #Lignes horizontales
    penup(),goto(-640, -300),pendown(),goto(640, -300),penup(),goto(-640, -240),pendown(),goto(640, -240),penup(),goto(-640, -190),pendown(),goto(640, -190),penup(),goto(-640, -140),pendown(),goto(640, -140),penup(),goto(-640, -100),pendown(),goto(640, -100),penup(),goto(-640, -70),pendown(),goto(640, -70),penup(),goto(-640, -40),pendown(),goto(640, -40),penup(),goto(-640, -15),pendown(),goto(640, -15),

On a par la suite énormément de goto afin de faire le quadrillage du pavage.

Pour produire l’image finale nous avons les appels des différents fonctions à la fin :

#appel de toutes les fonctions
fond(), etoile(), soleil(), montagne(), ville(), pavage()

Et pour exporter l’image finale en .png il y a la suite du script pour exporter une image générée par turtle en .png utilisé au début du script.

#enregistrement de l'image finale avec vérification des modules importés
image = getcanvas()
nom_du_fichier_sans_extension=titre+"_"+hex(randint(2**30+2**25,2**30+2**25+2**24-1))[2:]
image.postscript(file=nom_du_fichier_sans_extension+".ps", colormode='color')
try:
    psimage = Image.open(nom_du_fichier_sans_extension+".ps")
    psimage.load(scale=2)
    psimage_resized = psimage.resize((1280, 720))
    psimage.save(nom_du_fichier_sans_extension+".png")
    print(nom_du_fichier_sans_extension+".png", psimage.size, "sauvegardé dans le dossier")    
except:
    if not pillow_installed:
        print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
        print("https://nsi.xyz/py2png")
    else:
        print("Oops! - 'ghostscript' not installed- RTFM :")
        print("https://nsi.xyz/py2png")
exitonclick()

Le script va donc générer une image en .ps et la convertir en .png avec un nom généré aléatoirement pour éviter que à chaque fois que vous générez une image l’image soit écrasée

Télécharger le .py

L’image finale