Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • master
1 result

Target

Select target project
No results found
Select Git revision
  • master
1 result
Show changes

Commits on Source 5

31 files
+ 560
26
Compare changes
  • Side-by-side
  • Inline

Files

+0 −5
Original line number Diff line number Diff line
package fr.univamu;

public class Main {

}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univamu.progav;

import fr.univamu.progav.td2.DebuggerTutorial;

public class Main {

  public static void main(String[] args) {

    new DebuggerTutorial().exoDebug(); // TD2
  }
}
Original line number Diff line number Diff line
@@ -36,13 +36,13 @@ public class ExercicesConditionnelle {
  // bénéficient d’un tarif réduit à 5 euros. Enfin, les personnes ayant un
  // abonnement annuel ne paient rien.

  public interface Costumer {
  public interface Customer {
    int age();
    boolean isUnemployed();
    boolean hasAnnualSubscription();
  }

  public static double getPrice(Costumer costumer) {
  public static double getPrice(Customer customer) {
    return 0;
  }

Original line number Diff line number Diff line
package fr.univamu.progav.td2;

public class ASimpleLoop {

  public static double nonTerminatingSum(int n) {
    double sum = 0;
    for (double i = 0; i != n; i = i + 0.1) {
      sum = sum + i ;
    }
    return sum;
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

import java.util.ArrayList;
import java.util.List;

public class BackPackSolver {



  private final List<Item> allItems;
  private final List<Item> currentBackpack = new ArrayList<>();
  private final int availableVolume;

  public BackPackSolver(List<Item> allItems, int availableVolume) {
    this.allItems = allItems;
    this.availableVolume = availableVolume;
  }


  public List<Item> findBestValueBackpack(int nextItemIndex) {
    if (nextItemIndex >= allItems.size()) {
      return new ArrayList<>(currentBackpack);
    }
    List<Item> backpack1 = findBestValueBackpack(nextItemIndex+1);
    int currentVolume = sumVolumes(currentBackpack);
    if (currentVolume + allItems.get(nextItemIndex).volume > availableVolume) {
      return backpack1;
    }
    currentBackpack.add(allItems.get(nextItemIndex));
    List<Item> backpack2 = findBestValueBackpack(nextItemIndex+1);
    return selectBestBackpack(backpack1, backpack2);
  }



  private List<Item> selectBestBackpack(List<Item> backpack1, List<Item> backpack2) {
    int value1 = sumValues(backpack1);
    int value2 = sumValues(backpack2);
    return (value1 >= value2)? backpack1 : backpack2;
  }

  public record Item(String name,int volume, int value) {
    @Override
    public String toString() {
      return name + " (Volume=" + volume + ", value=" + value + ")";
    }
  }

  private static int sumValues(List<Item> backpack1) {
    return backpack1.stream().mapToInt(Item::value).sum();
  }

  private int sumVolumes(List<Item> backpack) {
    return backpack.stream().mapToInt(Item::volume).sum();
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

public class DebuggerTutorial {

  private int x = 2;
  private String text = "an instance variable of a DebuggerTutorial instance";

  public void exoDebug() {
    double x = 1;
    f();
    A a = new A();
    a.g();
    for (int i = 0; i < 100000; i++) {
      String s = "Reprendre l'exécution pour passer la boucle";
    }
    String r = "Si vous voyez ceci dans le débugger, c'est GAGNÉ";
    System.out.println("The end.");
  }

  public void f() {
    System.out.println("In method f.");
    double x = 0;
    String bad = "Si vous voyez ceci dans le débugger, c'est PERDU.";
    double y = 0;
  }

  class A {
    private final int x = 42;

    public void g() {
      String bad = "Si vous voyez ceci dans le débugger, c'est PERDU.";
      System.out.println("In method g.");
    }
  }


}
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

public class GuessingGame {

  public static int solve(int mystery) {
    return new GuessingGame(mystery).nbAttempts();
  }

  public static final int LOWER_BOUND = 1;
  public static final int UPPER_BOUND = 1000;

  private final int mystery;
  private int attempts = 0;

  public GuessingGame(int mystery) {
    this.mystery = mystery;
    guess(LOWER_BOUND, UPPER_BOUND);
  }

  private int nbAttempts() {
    return attempts;
  }

  private void guess(int lowerBound, int upperBound) {
    this.attempts++;
    if (lowerBound == upperBound) {
      return;
    }
    int middle = (upperBound + lowerBound) / 2;
    if (middle == mystery) {
      return;
    }
    if (middle < mystery) {
      guess(middle,upperBound);
    } else {
      guess(lowerBound,middle-1);
    }

  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

import java.util.List;

public class People {

  private final String name;
  private final int age;

  public People(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public int getAge() {
    return age;
  }

  /** Decides whether the list contains a 25-year-old "Charlie"
   * @param peopleList
   * @return true if a 25-year-old charlie is in the list
   */
  public static int whereIsCharlie(List<People> peopleList) {
    People charlie = new People("Charlie", 25);
    int count = 0;
    for (People p : peopleList) {
      if (p == charlie) {
        return  count;
      }
      count++;
    }
    return -1; // Charlie is not here.
  }


  @Override
  public String toString() {
    return this.name;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

public class Ratio {

  private final int num;
  private final int denom;

  private Ratio(int num, int denom) {
    this.num = num;
    this.denom = denom;
  }

  /** Builds a ratio, given its numerator and denominator
   * @param num the numerator of the ratio
   * @param denom the denominator of the ratio
   * @return a reduced ratio equals to num/denom, represented in reduced form.
   */
  public static Ratio of(int num, int denom) {
    int d = gcd(denom, num);
    return new Ratio(num / d, denom /d );
  }

  // UnsafeOf is used in test, to build a ratio without reducing it,
  // and must be used with already reduced numerator and denominator.
  protected static Ratio unsafeOf(int num, int denom) {
    return new Ratio(num, denom);
  }

  // Euclid's algorithm
  public static int gcd(int a, int b) {
    return a == 0 || b == 0? a + b:
           gcd(b, a % b);
  }


  public Ratio plus(Ratio r) {
    return of(this.num * r.denom + this.denom * r.num, this.denom * r.denom);
  }


  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof Ratio r)) {
      return false;
    }
    return r.num == this.num && r.denom == this.denom;
  }

  @Override
  public String toString() {
    double value = this.num / (double) this.denom;
    return String.valueOf(value);
  }
}
Original line number Diff line number Diff line
Introduction
============

Dans les exercices suivants, chaque petit programme comporte une 
erreur, qui 
apparait lors du test. L'objectif est d'apprendre à utiliser le débugger 
pour Java d'IntelliJ pour trouver la cause de l'erreur, et la corriger.

La tâche Gradle permet de lancer les tests, mais on préfèrera cette fois 
lancer uniquement le test de l'exercice en cours. Pour cela, ouvrir le 
fichier contenant le test, trouver la méthode de test, et dans la marge 
`clic gauche` sur l'icône de lancement ![run](../../../../../resources/run.png),
et choisir l'option *debug* ![debug](../../../../../resources/debug.png).

Pour arrêter le débugger à une instruction du programme, il faut placer des 
*breakpoints* ![breakpoint](../../../../../resources/breakpoint.png). Il suffit 
pour cela d'un `clic gauche` dans la marge du programme, sur le numéro de 
ligne. Un `clic droit` permet de le paramétrer si nécessaire, et un deuxième 
`clic gauche` le fait disparaître.

Lorsque le programme s'exécute, il s'interrompt automatiquement aux 
breakpoints, et affiche l'état de la pile.

![Panneau de débuggage](../../../../../resources/debug-panel.png)

Dans la partie gauche se trouve la liste des *frames*, c'est-à-dire des 
niveaux ou couches de la pile, la plus récente en haut. Attention, lancer un 
test demande un grand nombre d'appels de méthode avant d'arriver à la 
méthode de test, donc la plupart des *frames* ne sont pas pertinents, seuls 
les frames les plus hauts, pour lesquels on reconnaît les méthodes du projet,
nous intéressent.

La partie droite affiche le contenu du frame courant, en commençant par la 
valeur de `this` (si la méthode n'est pas statique), puis toutes les 
variables et leurs valeurs. Les tableaux et les objets peuvent être 
inspectés en dépliant les arborescences.

La barre du haut contient les actions réalisables, dont voici les plus 
importantes.

![Relancer](../../../../../resources/rerun.png) relance le test depuis le 
début, toujours en mode *debug*.

![Arrêter](../../../../../resources/stop.png) arrête l'évaluation du 
programme immédiatement, et ferme le débuggeur.

![Reprendre](../../../../../resources/resume.png) reprend l'évaluation, 
jusqu'au prochain *breakpoint* ou la fin normale de l'exécution du programme.

![Passer](../../../../../resources/step-over.png) passe à l'instruction 
suivante, en ignorant tout appel de méthodes dans l'instruction en cours.

![Entrer](../../../../../resources/step-into.png) passe à la première 
instruction d'une méthode appelée dans l'instruction en cours. En cas de 
choix entre plusieurs méthodes (ou constructeurs), il faut cliquer sur celle 
qui nous intéresse. Il est conseillé de ne pas entrer dans les méthodes ne 
faisant pas partie du projet.

![Sortir](../../../../../resources/step-out.png) reprend l'exécution jusqu'à 
terminer la méthode actuellement en cours, et s'interrompt à l'instruction 
ayant appelé la méthode.

Ces actions permettent d'exécuter le programme pas-à-pas, plus ou moins 
finement, en inspectant les valeurs des variables. 


Exercice 1
==========

Ce petit exercice vous permet de prendre en main le débugger d'IntelliJ.

- Vérifier que la méthode exécutable `main` de la classe `Main` (fichier `fr.
univamu.progav.Main.java`) appelle bien la méthode `exoDebug` d'une instance de 
  la classe `DebuggerTutorial` (sinon appeler l'enseignant).
- Exécuter le programme (tâche gradle run). Le programme doit afficher :
```
In method f.
In method g.
The end.
```
- Placer un *breakpoint* sur la première 
  ligne de la méthode 'main' (comment ? lire ci-dessus). Relancer le programme 
  en mode debug (bouton ![debug](../../../../../resources/debug.png) en haut 
  à droite). À l'issue de la compilation, vous obtiendrez l'ouverture de la 
  vue du debugger.
- Inspecter l'objet `this`. Quelles sont ses propriétés et leurs valeurs ? 
  Ceci correspond-il bien au programme écrit ?
- Avancer l'exécution d'une instruction 
  ![Passer](../../../../../resources/step-over.png). Quel est l'effet de 
  l'instruction ? 
- Entrer dans l'exécution de la méthode `f`
  ![Entrer](../../../../../resources/step-into.png). Combien la pile 
  a-t-elle de couches ? Quelles sont les valeurs de la variable `x` dans les 
  différentes couches de la pile ?
- Ressortir de la méthode `f`
  ![Sortir](../../../../../resources/step-out.png). Exécuter l'instruction 
  créant une instance de la classe `A` et vérifier son effet sur la mémoire. 
  Quelle est la référence du nouvel objet ?
- Sauter l'appel de la méthode `g`
  ![Passer](../../../../../resources/step-over.png).
- Ajouter un breakpoint après la boucle, puis reprendre l'exécution du 
  programme ![Reprendre](../../../../../resources/resume.png).
- Continuer jusqu'à voir le message de victoire dans le débugger. Sinon 
  recommencer.


Exercice 2
==========

Dans la classe `People`, la méthode `whereIsCharlie` devrait retourner la 
position de Charlie, 25 ans, dans la liste. Utiliser le test et le débuggeur 
pour trouver l'erreur.

Exercice 3
==========

Dans la classe `ASimpleLoop`, la méthode `nonTerminatingSum` fait un calcul, 
qui ne termine pas. Utiliser le test et le débuggeur, pour comprendre 
pourquoi elle ne termine pas. Corriger ensuite la méthode pour que le calcul 
s'arrête,

Exercice 4
==========

Dans la classe `Ratio`, représentant les nombres rationnels, l'addition ne 
semble pas produire le bon résultat. Pourtant, nous avons pris soin de bien 
réduire les fractions en calculant le plus grand commun diviseur avec 
l'algorithme d'Euclide, et de forcer cette réduction dans la méthode 
statique `of` que nous utilisons pour construire les fractions. Pour être 
sûr de bien tester, nous avons aussi ajouter une méthode `unsafeOf`, qui 
ignore l'étape de réduction : ainsi les valeurs attendues dans les tests 
sont certainement bien définies (nous les avons réduites nous-mêmes). Enfin, 
la méthode de test d'égalité profite de la forme réduite : il suffit de 
tester l'égalité des numérateurs et des dénominateurs. Utiliser la méthode 
de test et le débuggeur pour trouver l'erreur et la corriger. 


Exercice 5
==========

La classe `GuessingGame` reprend la stratégie optimale pour le jeu 
consistant à trouver un entier d'un intervalle (par exemple entre 1 et 1000),
en tentant des valeurs, et en obtenant pour chaque mauvaise réponse une 
indication "plus petit" ou "plus grand". Bien sûr, il s'agit de faire une 
recherche dichotomique. Ici, une erreur a été faite, et la dichotomie ne 
termine pas toujours. Il va d'abord falloir trouver une valeur mystère pour 
laquelle l'algorithme boucle infiniment (provoquant un dépassement de pile). 
Ensuite, en utilisant le débuggeur et en partant avec cette valeur, il sera 
possible de repérer la raison pour laquelle l'algorithme boucle ainsi. 
Utiliser donc une fois de plus le débugger pour trouver et corriger l'erreur.
 No newline at end of file
Original line number Diff line number Diff line
@@ -21,7 +21,12 @@ class ExercicesBouclesTest {
    Person mother,
    Person father,
    List<Person> children
  ) implements Person {}
  ) implements Person {
    @Override
    public String toString() {
      return this.name;
    }
  }

  private static final Person alfa =
    new MockPerson(78,"Alfa",true,null,null, new ArrayList<>());
Original line number Diff line number Diff line
@@ -57,12 +57,12 @@ class ExercicesConditionnelleTest {
    }
  }

  record MockCostumer(
  record MockCustomer(
    int age,
    boolean isUnemployed,
    boolean hasAnnualSubscription,
    double price
  ) implements ExercicesConditionnelle.Costumer {
  ) implements ExercicesConditionnelle.Customer {
    @Override
    public String toString() {
      return "Âge " + age + " "
@@ -71,26 +71,26 @@ class ExercicesConditionnelleTest {
    }
  }

  private List<MockCostumer> costumers =
  private List<MockCustomer> costumers =
    List.of(
      new MockCostumer(28,false,false,10),
      new MockCostumer(19,false,false,10),
      new MockCostumer(18,false,false,5),
      new MockCostumer(28,true,false,5),
      new MockCostumer(28,false,true,0),
      new MockCostumer(28,true,true,0),
      new MockCostumer(18,true,false,5),
      new MockCostumer(18,false,true,0),
      new MockCostumer(18,true,true,0),
      new MockCostumer(15,false,false,5),
      new MockCostumer(15,true,false,5),
      new MockCostumer(15,false,true,0),
      new MockCostumer(15,true,true,0)
      new MockCustomer(28,false,false,10),
      new MockCustomer(19,false,false,10),
      new MockCustomer(18,false,false,10),
      new MockCustomer(28,true,false,5),
      new MockCustomer(28,false,true,0),
      new MockCustomer(28,true,true,0),
      new MockCustomer(18,true,false,5),
      new MockCustomer(18,false,true,0),
      new MockCustomer(18,true,true,0),
      new MockCustomer(15,false,false,5),
      new MockCustomer(15,true,false,5),
      new MockCustomer(15,false,true,0),
      new MockCustomer(15,true,true,0)
      );

  @Test
  void getPriceTest() {
    for (MockCostumer costumer : costumers) {
    for (MockCustomer costumer : costumers) {
      double price = ExercicesConditionnelle.getPrice(costumer);
      assertEquals(costumer.price, price,
        "prix incorrect dans le cas :  " + costumer);
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

import org.junit.jupiter.api.Test;

import static fr.univamu.progav.td2.ASimpleLoop.nonTerminatingSum;
import static org.junit.jupiter.api.Assertions.*;

class ASimpleLoopTest {

  @Test
  void nonTerminatingSumTest() {
    double result = nonTerminatingSum(10);
    assertEquals(505,result);
  }
}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

class BackPackSolverTest {


  private final static List<BackPackSolver.Item> ITEMS =
    List.of(
      new BackPackSolver.Item("Alfa",5,8),
      new BackPackSolver.Item("Bravo",4,7),
      new BackPackSolver.Item("Charlie",4,6),
      new BackPackSolver.Item("Delta",3,4),
      new BackPackSolver.Item("Echo",2,3)
    );
  public static final int AVAILABLE_VOLUME = 10;

  @Test
  void findBestValueBackpack() {
    BackPackSolver bp = new BackPackSolver(ITEMS, AVAILABLE_VOLUME);
    List<BackPackSolver.Item> selection = bp.findBestValueBackpack(0);
    int totalVolume = selection.stream().mapToInt(BackPackSolver.Item::volume).sum();
    int totalValue = selection.stream().mapToInt(BackPackSolver.Item::value).sum();
    assertTrue(totalVolume <= AVAILABLE_VOLUME);
    assertEquals(16,totalValue);
    assertEquals(3,selection.size());
  }
}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

import org.junit.jupiter.api.Test;

import static fr.univamu.progav.td2.GuessingGame.LOWER_BOUND;
import static fr.univamu.progav.td2.GuessingGame.UPPER_BOUND;
import static org.junit.jupiter.api.Assertions.*;

class GuessingGameTest {

  @Test
  void solve() {
    int max_allowed = // a bound on the minimum number of guesses by the best strategy.
      (int) Math.ceil(log2(GuessingGame.UPPER_BOUND - GuessingGame.LOWER_BOUND + 2,1e-1));
    for (int i = GuessingGame.LOWER_BOUND; i <= GuessingGame.UPPER_BOUND; i++) {
      int r = GuessingGame.solve(i);
      assertTrue(r <= max_allowed,
        "Guessing " + i + " in " + r + "/" + max_allowed + " attempts");
    }
  }

  // compute log(x) in base 2, with given precision, for instance log2(x,1e-6)
  // is at most 0.000001 away from the exact value.
  private static double log2(double x, double precision) {
    return
      (x >= 2)? 1 + log2(x/2, precision):
      (x == 1)? 0:
      (x < 1)? - log2(1/x, precision):
      (precision > 1) ? 0:
      0.5 * log2(x * x, precision*2);
  }
}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

import org.junit.jupiter.api.Test;

import java.util.List;

import static fr.univamu.progav.td2.People.whereIsCharlie;
import static org.junit.jupiter.api.Assertions.*;

class PeopleTest {

  private final List<People> peopleList =
    List.of(
      new People("Alfa", 12),
      new People("Bravo", 18),
      new People("Charlie", 25),
      new People("Delta", 36),
      new People("Echo", 8),
      new People("Foxtrot", 11),
      new People("Golf", 21),
      new People("Hotel", 53),
      new People("India", 42),
      new People("Juliett", 28)
    );


  @Test
  void whereIsCharlieTest() {
    int charliePosition = whereIsCharlie(peopleList);
    assertEquals(2, charliePosition);
    List<People> noCharlie =
      peopleList.stream().filter(p -> !p.getName().equals("Charlie")).toList();
    int noCharliePosition = whereIsCharlie(noCharlie);
    assertEquals(-1, noCharliePosition);
  }
}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univamu.progav.td2;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class RatioTest {


  @Test
  void plusTest() {
    assertEquals(Ratio.unsafeOf(2,1),Ratio.of(1,1).plus(Ratio.of(1,1)));
    assertEquals(Ratio.unsafeOf(5,6),Ratio.of(1,3).plus(Ratio.of(1,2)));
    assertEquals(Ratio.unsafeOf(1,6),Ratio.of(-1,3).plus(Ratio.of(1,2)));
    assertEquals(Ratio.unsafeOf(-1,6),Ratio.of(1,3).plus(Ratio.of(-1,2)));
    assertEquals(Ratio.unsafeOf(-5,6),Ratio.of(-1,3).plus(Ratio.of(-1,2)));
    assertEquals(Ratio.unsafeOf(-5,6),Ratio.of(1,-3).plus(Ratio.of(1,-2)));
    assertEquals(Ratio.unsafeOf(5,6),Ratio.of(-1,-3).plus(Ratio.of(1,2)));
  }

}
 No newline at end of file