Table of Contents

Proiect - Etapa 2 - Sistem energetic

Obiective

Scenariu

Rețeaua de curent electric a unei țări este un sistem complex, format din producători, distribuitori, consumatori (casnici sau industriali) și instituții ale statului care reglementează și supraveghează buna funcționare a sistemului.

Etapa trecută s-a bazat pe interacțiunea dintre două entități - consumatori și distribuitori. În cadrul acestei etape, vom mai adăuga o entitate - producătorii - și vom extinde responsabilitățile distribuitorilor, păstrând în același timp și funcționalitățile de bază din prima etapă.

Consumatori

Aceștia funcționează ca în etapa trecută, cu o singura precizare suplimentară:

În cazul în care un consumator ramane cu o datorie în ultima lună de contract, acesta va fi în una din două situații:

Distribuitori

În aceasta etapă, distribuitorii vor interacționa și cu producătorii. În ceea ce privește consumatorii, interacțiunea va fi cea de la etapa anterioară, singura modificare fiind dată de înlocuirea costului de producție cu un cost obținut din cumpărarea energiei de la producători.

Interacțiunea cu producătorii:

Schimbări lunare date de simulare:

În input și în schimbările lunare s-a eliminat costul de producție pentru că acesta va fi calculat pe baza energiei luate de le producători.

Producători

Aceștia reprezintă noua entitate introdusă în această etapă. Un producător va produce energie de un anumit tip și o vinde mai multor distribuitori.

Proprietățile unui producător:

Schimbări lunare date de simulare:

Condiții, simplificări:

Strategii de alegere producători

Dacă și tipul și prețul și cantitatea sunt identice atunci producătorii se aleg în ordinea id-urilor lor.

Detalii de implementare

Mecanismul simulării și părțile de input și output sunt similare celor de la prima etapă. Simularea se bazează pe luni (runde), al căror număr este fixat din input (numberOfTurns), și se termină când au fost rulate numberOfTurns + 1 runde și se afișează starea curentă a simulării. În cazul în care toți distribuitorii dau faliment, simularea se va încheia.

Input, Output, Rulare

Atât inputul, cât și outputul vor fi de tip json. Pentru exemple despre cum să citiți/scrie fișiere JSON folosind biblioteca jackson aveți acest tutorial pe wiki. Puteți folosi și alte biblioteci pentru citirea lor însă să cereți întâi responsabililor temei (pe forum) adăugarea acelor jar-uri și pe vmchecker.

Inputul este același pentru consumatori și are modificări pentru distribuitori și producători.

Click pentru exemplu input

Click pentru exemplu input

{
  "numberOfTurns": 6,
  "initialData": {
    "consumers": [
      {
        "id": 0,
        "initialBudget": 150,
        "monthlyIncome": 28
      }
    ],
    "distributors": [
      {
        "id": 0,
        "contractLength": 6,
        "initialBudget": 60,
        "initialInfrastructureCost": 24,
        "energyNeededKW": 1930,
        "producerStrategy": "GREEN"
      }
    ],
    "producers": [
      {
        "id": 0,
        "energyType": "WIND",
        "maxDistributors": 10,
        "priceKW": 0.01,
        "energyPerDistributor": 2695
      }
    ]
  },
  "monthlyUpdates": [
    {
      "newConsumers": [
        {
          "id": 0,
          "initialBudget": 140,
          "monthlyIncome": 24
        }
      ],
      "distributorChanges": [
        {
          "id": 0,
          "infrastructureCost": 20
        }
      ],
      "producerChanges": [
        {
          "id": 0,
          "energyPerDistributor": 6319
        }
      ]
    },
    {
      "newConsumers": [
        {
          "id": 0,
          "initialBudget": 56,
          "monthlyIncome": 97
        }
      ],
      "distributorChanges": [
        {
          "id": 0,
          "infrastructureCost": 25
        }
      ],
      "producerChanges": [
        {
          "id": 0,
          "energyPerDistributor": 4430
        }
      ]
    },
    {
      "newConsumers": [
        {
          "id": 0,
          "initialBudget": 188,
          "monthlyIncome": 43
        }
      ],
      "distributorChanges": [
        {
          "id": 0,
          "infrastructureCost": 17
        }
      ],
      "producerChanges": [
        {
          "id": 0,
          "energyPerDistributor": 9965
        }
      ]
    },
    {
      "newConsumers": [
        {
          "id": 0,
          "initialBudget": 55,
          "monthlyIncome": 65
        }
      ],
      "distributorChanges": [
        {
          "id": 0,
          "infrastructureCost": 17
        }
      ],
      "producerChanges": [
        {
          "id": 0,
          "energyPerDistributor": 2569
        }
      ]
    },
    {
      "newConsumers": [
        {
          "id": 0,
          "initialBudget": 163,
          "monthlyIncome": 27
        }
      ],
      "distributorChanges": [
        {
          "id": 0,
          "infrastructureCost": 13
        }
      ],
      "producerChanges": [
        {
          "id": 0,
          "energyPerDistributor": 9077
        }
      ]
    },
    {
      "newConsumers": [
        {
          "id": 0,
          "initialBudget": 140,
          "monthlyIncome": 85
        }
      ],
      "distributorChanges": [
        {
          "id": 0,
          "infrastructureCost": 16
        }
      ],
      "producerChanges": [
        {
          "id": 0,
          "energyPerDistributor": 4523
        }
      ]
    }
  ]
}

Output-ul este același ca în etapa 1 pentru distribuitori și consumatori, iar pentru producători vom avea update-uri lunare despre câți distribuitori au avut.

Click pentru exemplu output

Click pentru exemplu output

{
  "consumers" : [ {
    "id" : 0,
    "isBankrupt" : false,
    "budget" : 178
  }, {
    "id" : 0,
    "isBankrupt" : false,
    "budget" : 152
  }, {
    "id" : 0,
    "isBankrupt" : false,
    "budget" : 446
  }, {
    "id" : 0,
    "isBankrupt" : false,
    "budget" : 324
  }, {
    "id" : 0,
    "isBankrupt" : false,
    "budget" : 208
  }, {
    "id" : 0,
    "isBankrupt" : false,
    "budget" : 209
  }, {
    "id" : 0,
    "isBankrupt" : false,
    "budget" : 213
  } ],
  "distributors" : [ {
    "id" : 0,
    "energyNeededKW" : 1930,
    "contractCost" : 12,
    "budget" : 261,
    "producerStrategy" : "GREEN",
    "isBankrupt" : false,
    "contracts" : [ {
      "consumerId" : 0,
      "price" : 22,
      "remainedContractMonths" : 0
    }, {
      "consumerId" : 0,
      "price" : 19,
      "remainedContractMonths" : 1
    }, {
      "consumerId" : 0,
      "price" : 9,
      "remainedContractMonths" : 2
    }, {
      "consumerId" : 0,
      "price" : 14,
      "remainedContractMonths" : 3
    }, {
      "consumerId" : 0,
      "price" : 4,
      "remainedContractMonths" : 4
    }, {
      "consumerId" : 0,
      "price" : 12,
      "remainedContractMonths" : 5
    }, {
      "consumerId" : 0,
      "price" : 12,
      "remainedContractMonths" : 5
    } ]
  } ],
  "energyProducers" : [ {
    "id" : 0,
    "maxDistributors" : 10,
    "priceKW" : 0.01,
    "energyType" : "WIND",
    "energyPerDistributor" : 4523,
    "monthlyStats" : [ {
      "month" : 1,
      "distributorsIds" : [ 0 ]
    }, {
      "month" : 2,
      "distributorsIds" : [ 0 ]
    }, {
      "month" : 3,
      "distributorsIds" : [ 0 ]
    }, {
      "month" : 4,
      "distributorsIds" : [ 0 ]
    }, {
      "month" : 5,
      "distributorsIds" : [ 0 ]
    }, {
      "month" : 6,
      "distributorsIds" : [ 0 ]
    } ]
  } ]
}

Pentru testarea soluției, rulați funcția main a clasei Test. Aceasta va rula atat testele, cat și checkstyle-ul. Pentru rularea checkerului, aveți nevoie ca proiectul vostru sa aiba încărcate bibliotecile pentru citirea fișierelor json. Mai multe detalii aici.

Dacă doriți să verificați individual un test, rulați main-ul din clasa Main dând ca argumente fișierul de intrare și fișierul de output.

Click aici pentru a vedea cum să dați argumente main-ului din IDE

Click aici pentru a vedea cum să dați argumente main-ului din IDE

Simularea

Simularea va fi aproape identică cu cea din etapa 1 a proiectului. Apariția producătorilor va introduce o nouă funcționalitate, astfel:

  1. La începutul primei luni, distribuitorii își vor alege un producător de la care vor cumpara energie lunar.
  2. Distribuitorii vor observa producătorii de la care iau energie, și își vor reaplica strategia de alegere producatori doar în lunile în care apare un update la vreunul din producători.

Runda inițială:

  1. Se încarcă datele de intrare despre distribuitori, consumatori și producători.
    • dacă păstrați liste pentru producători să le aveți sortate crescător în funcție de id-ul lor.
  2. Distribuitorii
    1. își aleg producătorii
    2. își calculează costul de producție
    3. își calculează costul inițial al contractelor
  3. Consumatorii - la fel ca la etapa 1
    1. își aleg distribuitorii și îi plătesc
  4. Distribuitorii obțin bani de la consumatori și își plătesc costurile, actualizând costul infrastructurii

Flow în fiecare lună:

Începutul lunii:

  1. se obțin noile valori din test
  2. se actualizează valorile pentru distribuitori
  3. se actualizează valorile pentru consumatori
  4. consumatorii își aleg distributorii și îi plătesc
  5. distribuitorii își plătesc costurile

În timpul lunii

  1. se actualizează valorile citite din test pentru luna respectivă pentru producători

La sfârșitul lunii

  1. toți distribuitorii non-bankrupt își actualizează producătorii dacă e cazul și își calculează costul de producție
    1. ordinea actualizării se face în ordinea crescătoare a id-urilor distribuitorilor
    2. în momentul în care unui distribuitor îi vine randul să își actualizeze producătorii, întâi se scoate acest distribuitor de la toți producătorii de la care lua energie și apoi se aplică strategia de alegere.
  2. se rețin câți distribuitori a avut fiecare producător

La finalul simulării se scriu în format json în fișierul de output - informațiile despre consumatori și distribuitori în mod similar primei etape - pentru fiecare producător câți distribuitori a avut în fiecare lună

:!: În momentul în care un distribuitor devine bankrupt, producătorii vor fi informați ca să nu mai îi dea energie (de exemplu dacă păstrați o listă în producător cu ce distribuitori are, îl scoateți din listă).

Formule

Formulele de la prima etapă rămân nemodificate, și se adaugă calcului costului de producție cerut fiecărui distribuitor:

Exemplu:

Distribuitorul D va lua energie de la A și de la C. Costul producției va fi: (1200 * 0.1 + 1800 * 0.2)/10 = 48

Design

Design-ul codului vostru ar trebui să fie cât mai decuplat și ușor de extins și urmărit. În afară de folosirea unor design patterns, în evaluarea temei o să luăm în considere aspecte legate de ce obiecte folosiți, ce relații aveți între ele, care este scopul lor, vizibilitatea câmpurilor și metodelor etc (exemplu de astfel de guidelines: clean code summary

Design patterns-urile pe care le recomandăm pentru aceasta etapă sunt Strategy și Observer. În mod evident, strategy merge folosit pentru alegerea producatorilor. Legat de observer, în situația din scenariul temei puteți să îl adaptați în mai multe feluri, nu vă impunem un anumit mod, este la latitudinea voastră cum alegeți să îl folosiți.

Câteva posibilități pentru aplicarea Observer:

Pentru a avea deja mecanismul de notificare dintre observers si observables, puteți folosi interfața Observer și clasa Observable din java.util. Dacă doriți puteți să vă implementați propriile interfețe/clase. Unul dintre motivele pentru care acest API ese deprecated din java 9 pentru că este prea simplu, însă acest lucru îl face potrivit pt tema și laborator. Într-o aplicație reală puteți folosi alte api-uri care sunt mult mai complexe și oferă foarte multe tipuri de obiecte și mecanisme (termenul folosit este reactive programming).

Indicații

Evaluare

Punctajul constă din:

Pe pagina Indicații pentru teme găsiți indicații despre scrierea readme-ului și depunctările generale pentru teme

Depunctarile pentru designul și organizarea codului se vor scădea din punctajul testelor.

Dacă vor apărea depunctari specifice temei în momentul evaluării, nemenționate pe pagina cu depunctări generale, ele se vor încadra în limitele de maxim 15 pentru design, 5p pentru readme. Dacă tema nu respecta cerințele, sau are zero design OOP atunci se pot face depunctari suplimentare.

Folosirea git pentru versionare va fi verificata din folderul .git pe care trebuie să îl includeți în arhiva temei. Punctajul se va acorda dacă ați făcut minim 3 commit-uri relevante și cu mesaj sugestiv.

Bonusuri: La evaluare, putem oferi bonusuri pentru design foarte bun, cod bine documentat dar și pentru diverse elemente suplimentare alese de voi.

Temele vor fi testate împotriva plagiatului. Orice tentativă de copiere va duce la anularea punctajului de pe parcursul semestrului şi repetarea materiei atât pentru sursă(e) cât şi pentru destinație(ii), fără excepție.

Checkstyle

Unul din obiectivele temei este învățarea respectării code-style-ului limbajului pe care îl folosiți. Aceste convenții (de exemplu cum numiți fișierele, clasele, variabilele, cum indentați) sunt verificate pentru temă de către tool-ul checkstyle.

Pe pagina de Recomandări cod găsiți câteva exemple de coding style.

Dacă numărul de erori depistate de checkstyle depășește 30, atunci punctele pentru coding-style nu vor fi acordate. Dacă punctajul este negativ, acesta se trunchiază la 0.

Exemple:

Upload temă

Arhiva pe care o veţi urca pe VMChecker va trebui să conţină în directorul rădăcină:

Resurse și linkuri utile