Version 0.3
[aspt.git] / performance.cc
1 /*******************************************************************
2 Jan Cermak | johniez | aspt.johniez.com
3 Creative Commons 2.5 Attribution-NonCommercial-NoDerivs 2.5 license
4 http://creativecommons.org/licenses/by-nc-nd/2.5/legalcode
5 *******************************************************************/
6
7 #include "performance.h"
8
9 /**
10  * \brief Init UI.
11  */
12 void PerformanceTab::init() {
13         QSettings settings("config/formation.ini", QSettings::IniFormat);
14         
15         format = new QComboBox();
16         format->addItem("---", QVariant(0));
17         format->addItem("5-4-1", QVariant(1));
18         format->addItem("5-3-2", QVariant(2));
19         format->addItem("4-3-3", QVariant(3));
20         format->addItem("4-4-2", QVariant(4));
21         format->addItem("4-5-1", QVariant(5));
22         format->addItem("3-4-3", QVariant(6));
23         format->addItem("3-5-2", QVariant(7));
24         format->setToolTip(tr("Team formation."));
25         
26         reorderPl = new QPushButton(tr("reorder players"));
27         reorderPl->setToolTip(tr("This button set on positions with wrong player type this player, who plays there (LM on LM post..)."));
28         
29         aggression = new QComboBox();
30         for(int i=0; i<=100; i+=5) {
31                 aggression->addItem(tr("aggression ") + QString().setNum(i) + "%", i);
32         }
33         aggression->setCurrentIndex(settings.value("aggr", 0).toInt()/5);
34         aggression->setToolTip(tr("Team aggression, same as you set in match."));
35         aggress = settings.value("aggr", 0).toInt();
36         
37         home = new QComboBox();
38         home->addItem(tr("play home"), 0.0);
39         home->addItem(tr("play away"), 0.1);
40         home->setToolTip(tr("Where you will play the match."));
41         
42         for(int j=0; j<11; ++j) {
43                 plCont[j] = new QHBoxLayout();
44                 player[j] = new QComboBox();
45                 orders[j] = new QComboBox();
46                 orders[j]->setToolTip(tr("'Ind. order' mean one of: Normal, Play along, Play along wing, Play it out, Passing, Own chance, Targetman and Free role."));
47                 orders[j]->addItem(tr("ind. order"), 0);
48                 for(int i=0; i<playerCnt; ++i) {
49                         int oldPenale = 0;
50                         int age = pls[i].age.toInt();
51                         double perf = ((pls[i].morale.toDouble()+pls[i].fitness.toDouble())/200)*pls[i].bestRate.toDouble();
52                         if(age > 30) {
53                                 oldPenale = (age-30)*3;         // 3 points penale per each year over 30
54                                 perf -= oldPenale;
55                         }
56                         player[j]->addItem("[" + pls[i].position + "] " + pls[i].fname + " " + pls[i].lname, QVariant(perf));
57                 }
58                 player[j]->setCurrentIndex(settings.value("Player/"+QString().setNum(j), 0).toInt());
59                 postLabel[j] = new QLabel("pos");
60                 plPerfLabel[j] = new QLabel(QString().setNum(player[j]->itemData(player[j]->currentIndex()).toDouble(), 'f', 2));
61                 plCont[j]->addWidget(postLabel[j]);
62                 plCont[j]->addWidget(player[j]);
63                 plCont[j]->addWidget(orders[j]);
64                 plCont[j]->addWidget(plPerfLabel[j]);
65         }
66         
67         container = new QHBoxLayout();
68         
69         container->addWidget(format);
70         container->addWidget(reorderPl);
71         container->addWidget(aggression);
72         container->addWidget(home);
73         mainLayout->addLayout(container);
74         for(int j=0; j<11; ++j) mainLayout->addLayout(plCont[j]);
75         
76         cButt = new QPushButton(tr("count team performance"));
77         mainLayout->addWidget(cButt);
78         
79         result = new QLabel(tr("Set formation, aggression and players.<br>") + "<span style=\"color:red\">" + tr("Results could be inaccurate!") + "</span><br>" + tr("This version do not penalize players at wrong position!<br>See http://flyspray.johniez.com/task/14"));
80         mainLayout->addWidget(result);
81         
82         format->setCurrentIndex(settings.value("form", 0).toInt());
83         formatChange(settings.value("form", 0).toInt());
84         
85         connect(format, SIGNAL(currentIndexChanged(int)), this, SLOT(formatChange(int)));
86         connect(aggression, SIGNAL(currentIndexChanged(int)), this, SLOT(aggressChange(int)));
87         connect(cButt, SIGNAL(clicked()), this, SLOT(recount()));
88         for(int i=0; i<11; i++) {
89                 connect(player[i], SIGNAL(currentIndexChanged(int)), this, SLOT(playerChange(int)));
90         }
91         connect(reorderPl, SIGNAL(clicked()), this, SLOT(reorderPlayers()));
92         mainLayout->update();
93 }
94
95 /**
96  * \brief Performance Tab constructor.
97  */
98 PerformanceTab::PerformanceTab(QWidget *parent): QWidget(parent), defs(0), mids(0), fors(0) {
99         mainLayout = new QVBoxLayout;
100         setLayout(mainLayout);
101         init();
102 }
103
104 /**
105  * \brief Performance Tab destructor.
106  */
107 PerformanceTab::~PerformanceTab() {
108         for(int i=0; i<11; ++i) {
109                 delete player[i];
110                 delete postLabel[i];
111                 delete plPerfLabel[i];
112                 delete orders[i];
113                 delete plCont[i];
114         }
115         delete format;
116         delete aggression;
117         delete home;
118         delete result;
119         delete cButt;
120         delete container;
121         delete reorderPl;
122         delete mainLayout;
123 }
124
125 /**
126  * \brief Slot assigned to data change action.
127  */
128 void PerformanceTab::dataChanged() {
129         container->removeWidget(format);
130         delete format;
131         container->removeWidget(aggression);
132         delete aggression;
133         container->removeWidget(home);
134         delete home;
135         container->removeWidget(reorderPl);
136         delete reorderPl;
137         mainLayout->removeWidget(reinterpret_cast<QWidget*>(container));
138         delete container;
139         
140         for(int i=0; i<11; ++i) {
141                 mainLayout->removeWidget(reinterpret_cast<QWidget*>(plCont[i]));
142                 delete plCont[i];
143                 delete player[i];
144                 delete plPerfLabel[i];
145                 delete postLabel[i];
146                 delete orders[i];
147         }
148         mainLayout->removeWidget(cButt);
149         delete cButt;
150         mainLayout->removeWidget(result);
151         delete result;
152         mainLayout->update();
153         init();
154 }
155
156 /**
157  * \brief Set adequate player post by selected formation.
158  */
159 void PerformanceTab::postLabels() {
160         int LMpos = 0;
161         if(!defsC) {
162                 for(int i=0; i<11; ++i) {
163                         postLabel[i]->setText("??");
164                 }
165         }
166         postLabel[0]->setText("GK");
167         postLabel[1]->setText("LB");
168         orders[1]->clear();
169         orders[1]->addItem(tr("ind. order"), 0);
170         orders[1]->addItem(tr("offensive"), 2);
171         postLabel[2]->setText("CB");
172         switch(defsC) {
173                 case 5:
174                         postLabel[3]->setText("SW");
175                         orders[3]->clear();
176                         orders[3]->addItem(tr("ind. order"), 0);
177                         postLabel[4]->setText("CB");
178                         orders[4]->clear();
179                         orders[4]->addItem(tr("ind. order"), 0);
180                         postLabel[5]->setText("RB");
181                         orders[5]->clear();
182                         orders[5]->addItem(tr("ind. order"), 0);
183                         orders[5]->addItem(tr("offensive"), 2);
184                         LMpos = 6;
185                         break;
186                 case 4:
187                         postLabel[3]->setText("CB");
188                         orders[3]->clear();
189                         orders[3]->addItem(tr("ind. order"), 0);
190                         postLabel[4]->setText("RB");
191                         orders[4]->clear();
192                         orders[4]->addItem(tr("ind. order"), 0);
193                         orders[4]->addItem(tr("offensive"), 2);
194                         LMpos = 5;
195                         break;
196                 case 3:
197                         postLabel[3]->setText("RB");
198                         orders[3]->clear();
199                         orders[3]->addItem(tr("ind. order"), 0);
200                         orders[3]->addItem(tr("offensive"), 2);
201                         LMpos = 4;
202                         break;
203         }
204         switch(midsC) {
205                 case 5:
206                         postLabel[LMpos]->setText("LM");
207                         postLabel[LMpos+1]->setText("CM");
208                         postLabel[LMpos+2]->setText("CM");
209                         postLabel[LMpos+3]->setText("CM");
210                         postLabel[LMpos+4]->setText("RM");
211                         break;
212                 case 4:
213                         postLabel[LMpos]->setText("LM");
214                         postLabel[LMpos+1]->setText("CM");
215                         postLabel[LMpos+2]->setText("CM");
216                         postLabel[LMpos+3]->setText("RM");
217                         break;
218                 case 3:
219                         postLabel[LMpos]->setText("LM");
220                         postLabel[LMpos+1]->setText("CM");
221                         postLabel[LMpos+2]->setText("RM");
222         }
223         for(int i=LMpos; i<LMpos+midsC; ++i) {
224                 orders[i]->clear();
225                 orders[i]->addItem(tr("ind. order"), 0);
226                 orders[i]->addItem(tr("defensive"), 1);
227                 orders[i]->addItem(tr("offensive"), 2);
228         }
229         switch(forsC) {
230                 case 3:
231                         postLabel[8]->setText("LF");
232                         orders[8]->clear();
233                         orders[8]->addItem(tr("ind. order"), 0);
234                         orders[8]->addItem(tr("defensive"), 1);
235                         postLabel[9]->setText("CF");
236                         orders[9]->clear();
237                         orders[9]->addItem(tr("ind. order"), 0);
238                         postLabel[10]->setText("RF");
239                         orders[10]->clear();
240                         orders[10]->addItem(tr("ind. order"), 0);
241                         orders[10]->addItem(tr("defensive"), 1);
242                         break;
243                 case 2:
244                         postLabel[9]->setText("CF");
245                         orders[9]->clear();
246                         orders[9]->addItem(tr("ind. order"), 0);
247                         postLabel[10]->setText("CF");
248                         orders[10]->clear();
249                         orders[10]->addItem(tr("ind. order"), 0);
250                         break;
251                 case 1:
252                         postLabel[10]->setText("CF");
253                         orders[10]->clear();
254                         orders[10]->addItem(tr("ind. order"), 0);
255                         break;
256         }
257 }
258
259 /**
260  * \brief Count performance of each line (def, mid, fwd).
261  *
262  * Count with offensive/defensive order of each player.
263  */
264 void PerformanceTab::countPerf() {
265         defs = 0;
266         mids = 0;
267         fors = 0;
268         double perf;
269         for(int i=0; i<=defsC; ++i) {
270                 perf = player[i]->itemData(player[i]->currentIndex()).toDouble();
271                 if(orders[i]->itemData(orders[i]->currentIndex()).toInt()==0) {
272                         defs += perf;
273                 } else {
274                         defs += (0.78 * perf);
275                         mids += (0.22 * perf);
276                 }
277         }
278         for(int i=defsC+1; i<=defsC+midsC; ++i) {
279                 perf = player[i]->itemData(player[i]->currentIndex()).toDouble();
280                 if(orders[i]->itemData(orders[i]->currentIndex()).toInt()==0) {
281                         mids += perf;
282                 } else if(orders[i]->itemData(orders[i]->currentIndex()).toInt()==1) {
283                         defs += (0.22 * perf);
284                         mids += (0.78 * perf);
285                 } else {
286                         fors += (0.22 * perf);
287                         mids += (0.78 * perf);
288                 }
289         }
290         for(int i=defsC+midsC+1; i<11; ++i) {
291                 perf = player[i]->itemData(player[i]->currentIndex()).toDouble();
292                 if(orders[i]->itemData(orders[i]->currentIndex()).toInt()==0) {
293                         fors += perf;
294                 } else {
295                         fors += (0.78 * perf);
296                         mids += (0.22 * perf);
297                 }
298         }
299 }
300
301 /**
302  * \brief Slot assigned to "count performance" button.
303  *
304  * Print all play-variants points..
305  */
306 void PerformanceTab::recount() {
307         double homeMod = home->itemData(home->currentIndex()).toDouble();
308         double pre = (1.0+((double)aggress/1000))/(7.0 - (club.spirit.toDouble()/1000) + homeMod);
309
310         countPerf();
311         QString text;
312         if(!defsC) text = tr("Choose a formation");
313         else {
314                 double O = pre*defs;
315                 double M = pre*mids;
316                 double F = pre*fors;
317                 text = "<table cellpadding=\"1\" width=\"100%\"><tr><td>----</td><td style=\"color:blue;\"  align=\"right\">"+tr("Long Ball")+"</td><td align=\"right\">"+tr("Without tactics")+"</td><td style=\"color:blue;\" align=\"right\">"+tr("Kick and rush")+"</td><td align=\"right\">"+tr("Passing")+"</td><td style=\"color:blue;\" align=\"right\">"+tr("Defensive wall")+"</td></tr><tr><td>D</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(O*1.05,'f',2)+"</td><td align=\"right\">"+QString().setNum(O,'f',2)+"</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(O*0.9,'f',2)+"</td><td align=\"right\">"+QString().setNum(O*0.9,'f',2)+"</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(O*1.08,'f',2)+"</td></tr><tr><td>M</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(M*0.9,'f',2)+"</td><td align=\"right\">"+QString().setNum(M,'f',2)+"</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(M*0.9,'f',2)+"</td><td align=\"right\">"+QString().setNum(M*1.1,'f',2)+"</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(M*0.9,'f',2)+"</td></tr><tr><td>F</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(F*1.05,'f',2)+"</td><td align=\"right\">"+QString().setNum(F,'f',2)+"</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(F*1.27,'f',2)+"</td><td align=\"right\">"+QString().setNum(F*0.9,'f',2)+"</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum(F*0.9,'f',2)+"</td></tr><tr><td>Sum</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum((O*1.05+M*0.9+F*1.05),'f',2)+"</td><td align=\"right\">"+QString().setNum((O+M+F),'f',2)+"</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum((O*0.9+M*0.9+F*1.27),'f',2)+"</td><td align=\"right\">"+QString().setNum((O*0.9+M*1.1+F*0.9),'f',2)+"</td><td style=\"color:blue;\" align=\"right\">"+QString().setNum((O*1.08+M*0.9+F*0.9),'f',2)+"</td></tr></table>";
318         }
319         result->setText(text);
320 }
321
322 /**
323  * \brief Slot assigned to aggression change.
324  *
325  * \param[in] a Aggression ID.
326  * Save aggression to config file.
327  */
328 void PerformanceTab::aggressChange(int a) {
329         aggress = a*5;
330         QSettings settings("config/formation.ini", QSettings::IniFormat);
331         settings.setValue("aggr", aggress);
332         settings.sync();
333 }
334
335 /**
336  * \brief Slot assigned to formation change.
337  * \param[in] t Formation ID.
338  */
339 void PerformanceTab::formatChange(int t) {
340         QSettings settings("config/formation.ini", QSettings::IniFormat);
341         if(t<8 && t>=0) { settings.setValue("form", t); settings.sync(); }
342         switch(t) {
343                 case 0: 
344                         defsC = 0; midsC = 0; forsC = 0;
345                         break;
346                 case 1:
347                         defsC = 5; midsC = 4; forsC = 1;
348                         break;
349                 case 2:
350                         defsC = 5; midsC = 3; forsC = 2;
351                         break;
352                 case 3:
353                         defsC = 4; midsC = 3; forsC = 3;
354                         break;
355                 case 4:
356                         defsC = 4; midsC = 4; forsC = 2;
357                         break;
358                 case 5:
359                         defsC = 4; midsC = 5; forsC = 1;
360                         break;
361                 case 6:
362                         defsC = 3; midsC = 4; forsC = 3;
363                         break;
364                 case 7:
365                         defsC = 3; midsC = 5; forsC = 2;
366                         break;
367         }
368         postLabels();
369         reorderPlayers();
370 }
371
372 /**
373  * \brief Slot assigned to player combobox changes.
374  * \param[in] id possition ID
375  */
376 void PerformanceTab::playerChange(int id) {
377         id = 1; //avoid warning :-D
378         QSettings settings("config/formation.ini", QSettings::IniFormat);
379         for(int i=0; i<11; ++i) {
380                 settings.setValue("Player/"+QString().setNum(i), player[i]->currentIndex());
381                 plPerfLabel[i]->setText(QString().setNum(player[i]->itemData(player[i]->currentIndex()).toDouble(), 'f', 2)); //player[i]->itemData(player[i]->currentIndex()).toInt()
382         }
383         settings.sync();
384 }
385
386 /**
387  * \brief Slot assigned to "re-order players" button.
388  *
389  * If there are players assigned to wrong possition (by selected formation),
390  * then this function give here players with correct post.
391  * This do not look at player performance, first is selected..
392  */
393 void PerformanceTab::reorderPlayers() {
394         int i;
395         int from = 0;
396         for(i=1; i<=defsC; ++i) {               // defenders
397                 if(i==1) {              // LB
398                         if(pls[player[i]->currentIndex()].position != "LB") {
399                                 player[i]->setCurrentIndex(findFirstOnPost("LB"));
400                         }
401                 } else if(i==defsC) {           // RB
402                         if(pls[player[i]->currentIndex()].position != "RB") {
403                                 player[i]->setCurrentIndex(findFirstOnPost("RB"));
404                         }
405                         // RB is last managed from defenders, should set finding from him
406                         from = player[i]->currentIndex();
407                 } else if(defsC == 5 && i==3) {         // SW
408                         if(pls[player[i]->currentIndex()].position != "SW") {
409                                 player[i]->setCurrentIndex(findFirstOnPost("SW"));
410                         }
411                 } else {                // CB
412                         if(pls[player[i]->currentIndex()].position != "CB") {
413                                 player[i]->setCurrentIndex(findFirstOnPost("CB"));
414                         }
415                 }
416         }
417         for(i=defsC+1; i<=defsC+midsC; ++i) {
418                 if(i==defsC+1) {                // LM
419                         if(pls[player[i]->currentIndex()].position != "LM") {
420                                 player[i]->setCurrentIndex(findFirstOnPost("LM"));
421                         }
422                 } else if(i==defsC+midsC) {             // RM
423                         if(pls[player[i]->currentIndex()].position != "RM") {
424                                 player[i]->setCurrentIndex(findFirstOnPost("RM"));
425                         }
426                         // RM is last managed from midfields, should set finding from him
427                         from = player[i]->currentIndex();
428                 } else {                // CM
429                         if(pls[player[i]->currentIndex()].position != "CM") {
430                                 player[i]->setCurrentIndex(findFirstOnPost("CM"));
431                         }
432                 }
433         }
434         for(i=defsC+midsC+1; i<=defsC+midsC+forsC; ++i) {
435                 if(forsC==3) {
436                         if(i==defsC+midsC+1) {          // LF
437                                 if(pls[player[i]->currentIndex()].position != "LF") {
438                                         player[i]->setCurrentIndex(findFirstOnPost("LF"));
439                                 }
440                         } else if(i==10) {              // RF
441                                 if(pls[player[i]->currentIndex()].position != "RF") {
442                                         player[i]->setCurrentIndex(findFirstOnPost("RF"));
443                                 }
444                         }
445                 } else {                // always CF
446                         if(pls[player[i]->currentIndex()].position != "CF") {
447                                 player[i]->setCurrentIndex(findFirstOnPost("CF"));
448                         }
449                 }
450         }
451 }
452
453 /**
454  * \brief Searching for first player with this post.
455  * \param[in] post player possition.
456  */
457 int PerformanceTab::findFirstOnPost(const QString &post) {
458         for(int i=0; i<playerCnt; ++i) {
459                 if(post == pls[i].position) return i;
460         }
461         return 0;
462 }