From 870e985af1139289d4ecfc440824885d24de5029 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Thu, 29 Aug 2024 11:15:48 +0200
Subject: [PATCH] Detect/manage end game

---
 android/gradle.properties                     |   4 +--
 assets/ui/game_draw.png                       | Bin 0 -> 170 bytes
 assets/ui/game_fail.png                       | Bin 3647 -> 170 bytes
 .../metadata/android/en-US/changelogs/3.txt   |   1 +
 .../metadata/android/fr-FR/changelogs/3.txt   |   1 +
 lib/cubit/game_cubit.dart                     |  15 +++++++--
 lib/models/game/game.dart                     |   9 ++++++
 lib/ui/widgets/game/game_board.dart           |   4 +--
 lib/ui/widgets/game/game_end.dart             |  29 +++++++++++++-----
 pubspec.yaml                                  |   2 +-
 resources/ui/images/game_draw.svg             |   2 ++
 resources/ui/images/game_fail.svg             |   2 +-
 12 files changed, 52 insertions(+), 17 deletions(-)
 create mode 100644 assets/ui/game_draw.png
 create mode 100644 fastlane/metadata/android/en-US/changelogs/3.txt
 create mode 100644 fastlane/metadata/android/fr-FR/changelogs/3.txt
 create mode 100644 resources/ui/images/game_draw.svg

diff --git a/android/gradle.properties b/android/gradle.properties
index 818e87b..db7a1ee 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx1536M
 android.useAndroidX=true
 android.enableJetifier=true
-app.versionName=0.0.2
-app.versionCode=2
+app.versionName=0.0.3
+app.versionCode=3
diff --git a/assets/ui/game_draw.png b/assets/ui/game_draw.png
new file mode 100644
index 0000000000000000000000000000000000000000..047508dc7427561315ec1c3834f25ab888324c06
GIT binary patch
literal 170
zcmeAS@N?(olHy`uVBq!ia0y~yU^oE6jLZxS3>iZITo@P_I14-?iy0W?oEaG8oERJS
zYjH3zFi4iTMwA5Sr<If^7Ns(jmzV2h=4BTrCl;jY<rk&TerF@az`(#9;1lBd|NsBx
zN2E_MFfcHd1o;IsI6S+N#=yWJ?djqeA|d(qpdljz1H&PO-^=58`4boz7#Iq4gbpw;
TwzFS+2jY3U`njxgN@xNAJ<2Yo

literal 0
HcmV?d00001

diff --git a/assets/ui/game_fail.png b/assets/ui/game_fail.png
index 93f2801f9d6bb2ce508e1293cd64d6ff2e9970ec..047508dc7427561315ec1c3834f25ab888324c06 100644
GIT binary patch
delta 97
zcmdllvx;$o1Scai0|P^b&_9=niZ;Fs%mF?juK)l4Uw%aT1Oo#DV@Z%-FoVOh8)*y-
z4AP!1jv*3~Zx0$WGB7Y4Quw_*j+Z}yfq{XcKu72R17kb;#djc{r>mdKI;Vst0G&A;
A+yDRo

delta 3601
zcmZ3*xL;<11Sba@0|P_QogDUwiZ=DUXFOdTLn>~)om-s~5-N9mcXrwTTRV11<!070
z)CNrW;jmg^y~mS_Tt|hNB!rpVo(eYSo!J#AV5pU$7!@rb=)Ex{>N49>?zKYmU0x~&
zzc{nkcy4<7vbR0DxtXcIm?mxh9`iCH>Ok4N?{hx?eJuRn_)Gb|`Jb(ypWFHTn1E9f
zL%qP%f<ONM*G;Hexi+`5-udt^JI`B1`*!`xWjMxlmhY^<*-4XDdQRWG)RHkzA|tEn
zQh03amB_HNRl4TaA4Y9ocl*<i$4912b9-`fa_5veJO^ehytz<vQDo8D`1`(_uSP~y
zb)~%x^7d9c8~26f#arJGp`lO9Yrf4)IeSLtLcg^8tNQ%?vJD%YH>cHqI{B|}k<!ZL
z%hcjeKHlNMRWSSgm6b{FcfU82RP#I1(6B;DRZVD?YpRjmnv~Di3b;N@w`+cQb@T6U
zHw9`IxC)+ocR&B_<=6kE`55!UqRtk+KGeEb!|Z~Qm)r02^KE|4opf`yld?l}bWnKZ
z&PJ&=CT6u=jzK~%>#fRs?%%&QO=1dz_?>s`x4XM^e*LHr5!<jeFwE%ozn{;iaqC^*
z(!jFd+nnEzxQlCZbhx-~xSY)Uz0g_g(k-jPHB5gdZxcB4r{SmHgb5CHt5;YoPWg2#
zkb6N+#r{cZzD|sc^3_dGQXZ{d_3Qo$mKRf>*54M>KXzH}fao?=@2cwF`eVNJY6s4~
zWo1nh;rZZEotSv|!|}!891m8n)LihE=_pf-UTaX0hkx$d<=2HCOuIHmhMkMGVp-|;
zyyF*?h3nV+ef_Fv<44v#%FCBcnzw5gzdOf;$e=~ejSU=get$Y`RkiJ`{(+<C&PATP
zy1G__Pk{0Ht*y`X%SwE{b1&G^vbXJH{o_Cx1(vqm@6~LrV&}y-6ubA=^&euG_(Dtn
z|2ch!>biZLu8dB9)dB(%WJDf(n|5|~y=!2DN5%Hs&lip_3~6Y8s~r~O5ZK^h5w=z;
zVAKDAGfUsSD|x-hRf9|5_1TR*JVhIKS390*IQ?}?<vAG<Ru0y)HfQU6=3o8gb9iz8
zB8_?njf`iR-xL`d7z7v`7(`ed7#I{77z7v?I2agM7#Nrs7#JBE7#Kjp4QUfEUFxWO
z8<li>*Hn{dPX&+P+xx0MH-E3I&g*M}mFHxd@@M^JT-$0>uD5Yb{Q7Gd8`Apj#B6Qj
z&Azt6w3R{1E$kngdzo40%Ju4T>%aSdjL=!~vHo#?r=e}^jR&)hj65FitIg7N3pS35
z{$2fEu<{rW$AYB~ti8QDu0NK%su0Kfy;JzemXuD5gYmnjnAHBxJ@9qW)-o}1;mThn
z90FUn&7I)z=KUUL8(-f>{wD@f{4xqvefF$N{k@cW+4<Yn#K~=sjy1Ztv4KJGh(Rh>
zVf|;{6KwTG8fUF!C#Ii&ruV1h{^g=yB@tQA)~!)#J2_d=!NqLH<z*9}-MY1bXG#6q
z)oVIm{+h9TYhCwMscW-LuU}b_%*=Sm^7Ha#la{SowSjNR{=L?7k4%|)vgSu`x0qo6
zUAc*~E_Qa7rE>`IJ$iigY?cb!C4I+a<;$~^f8{T)cUH-M_U~7Hw%RwAGn@(cH!3e;
zKDmqKBFBG)FArH*I6f{u7hw1HVXdXe$<*_qub1{rwaFG^;SgQ7Y10Z`wd}bHvyA@-
z#4KGZprEq(|C^hE@;+fI7rcJ3*XvyV^f)DrrJ&|RV;akaPemHHPS0EYj<xJ<6N96m
zxO-GeWN`DUqkaok&a8j&UbCK!d1ZfZD+8l`{gmD**Vsa{=Q?y7{}0$w71zPZ_~K*C
zTD~=6R*hll{}#@eU(LtF^5;$c?=oNhJQLLf#Xlld5qwN69JcG%e`V}DR^;*e^t^=@
z-`+GbFmekVTD*Ht2~${F-G9N)O-vjD8yM!-96ICRzDRh5@&3aHLwqyD+Zh_`-!YcG
zP0HGE_$Ft>?4N(V7re>g5YV_bJuWHlz~PIW5p#aBZ`|{NiG?HWL8Q!=fHJ1A^nZ>$
z++q$54W1qW>A``j3ATT>WMBMlq2M53!OcCB*TLYl;<V|u&iaxEA{Qk5UwC@Dv22rr
z72|8;{|d`ePb)ZFIC5;#vdQW<rzcFA+fd&=GrrdT$MpCshkFDRME>6hT|I;UNQM=o
zzOnt%#G_n$1cWbbKjh`Tb6Ugl50_{E`rua}vCbv)+UuVa5^fZAOi%6q#n+%>SZK;M
z`8(6a^iw+aVzP>jMz2>J+w0d)zI3qX^Yh1X3pUt`c0J-1TsW;^`iIMg3zM5?KU69d
ztGj9RsJ?XfPYynQCGF(IsGUOP%}z`$@=Ok75WI3Zk1hWk;#}Z0VJa)9KwTkg0}IFg
z4<NJRD;O0R59#k=nBef{gENDNLdg$B1{DFTKLQRV^_(pH_ACOCAR9Tf84vL@woGMs
z*v@dstKow)!$mtk!$(rbj&>Vv6L8q`A-+)itFV7Uk77f`!~Ksw-TG3}W6C0+|Hs)r
zCOu|{0Fwj5$3yS;AHJWYc&zfX0s}}Y+~dQIWC4d1Mi<`w^_ELK6wc4(W^@s8`10Ym
zb>m5wC-pOp6&VicZ(wm#o|t~7fq`TH0ihE{6PNq9gP9&e6Xhydm=yjnc?ZP%FJYH&
z0SnKubY7BqSplqZxxetsf4@P7=$$Psb=mdaj-%m2w|8);=)`4ytsv!d8@vk6+X^r|
z6pv;)JVg`4sIdI<xc|t6Nlf*O0(Fh5KOV9#^7m_F;Mo5_NJZ6=p(Q?nbKn1YFNB4`
z=Ds`SwP?NpBg7ej2bZw;a5sF&_Gx;2ytD341&6@I=-XoYVfs~%9!+)GJy)7D#=URC
zuND>#0lyc&SIf=r?U$eSV&mg2CP}xq^-6QjX>DC%r^m<C!u;z<W4+wDM^BGVUYH+$
z^Ik=>G-poqHiw3S2Rd4hvYyHR`~L9~r_I^3M=a{?SU6tps(%@zm;O&ssNfRkmHQmW
zdYc&*Hi=F7{^7G)W98Q@j)t56f1RF}?RDT_QHR|01_s3i9}h4prq#(=H-gKKt{)Z4
z>OV-mK65@=eSwg3Lqgrh*!m3)H$Hq;X#9P{kVAlHn(yqEsBa&($t<#ua%xa0cymYd
z&6)Gw>IOdZco>=PF}%O6{^iVhXY~uOLc4P~3O+3OU~K<-uERWIcBT*a7!TQg-h78s
z$xyREyP@_t-<dx><xFe$S)XZPc*ZL&P}ipV!NlZ&W<bF6|5LvzPqTfa*B-O9eyM<h
z#-m49B3X>>XU{$G>y);D!i(O5IJvYsG3&<T&P&+k8W<eq+h>^b8{0R}J@EBvxCO72
zR*ZYU(w`nrhyIPu4Fdak-sff>+|)kt>4Yk0mbgxyk2@E9zkmG9c?b0c$FE1O5U;+z
z=uTn#uW5pZ*5`7bId9h;t$3(4@m0vz$GP<p-!h6VQ||AR6;E!hwO`OOsqVDd8sq(b
z$G@DhmwEl{Y$E@DW%c$e$B#KRbd)qzzvsPObfWeVOZol7LGgN3|0*Aq?mSe)KjH1w
z@IuQxlW#2FVs~F*<T&YIX8QNup~sJR{xw@?Q*D;{>*ewbrKfI1CHeRt|N7#ho&FOo
zZSGg%-u3C8oD(hoMf?yA_t9#Kj;{&4`+(gha>m&sziwr_)IXp5!=Y`O%L3WNEzGxz
zp79i>qzhL*^HFTFZ)#yls(U8+^}wv~mvxI@PWYl)e)?GNnb=mnE9pV(=BG*uUJ47i
z=jj!`x$7+>U+0k%y?s)fY4(m=589S!-zgP0)QwzJ#%5KoY4Yx#uT1qff#2um9{Kg@
z^pPo3U3rAni@ur{|6f{x*%n}FU|?W!U|?WWU}#{_;DR&_ScDP|JgvI5=A!i-Mh<b4
z&nCYOr|;T*d2P4YLJbFvHIkA~lESb5k#IV3xNoX9dw__7P~Y--pyrA|z32n8^RL%e
z2Z|^N-7~-cMdRlFRxW{JGyD53ix?(m=xZ2Udb66TWa{+#_C*X61C0K!jc<^fo43BP
zS$r;|1aBLsut$Du?7H}d?zwY~=Vo7<<6hXnVR3z(ZT-T<j|KNLOgT46NVbdF<-wha
z%DWEU`OW&_>eZ(nlhqbFG-N-y67s12@=H4j#fC%sql$}UG=v_^+}3ZmNjq}?*DR(Z
zU#?tx=B=rzA@ZR7+xoS4?M*(1b1W!Gu6AUs6K06HRQO|q=gA+w*M$|9UC+3aa{A00
z$Ab*v?(&;9)$HB$=g@~e{Q?g@1-;-fJJKM&<Vnh<;Mmx@t!v^#8Fq>MTD#~`kDVeT
zD@(nPv+<qS$jYdbU+j-5Irz*!UL2lYxN)VO9$za<j*ztXt?n+JziZbDubcWgo6BM6
zgA%(1IWlLe`u5La`Z4#XbyxRU@u;YG`{RzS*JfC{f35Du*EbApW8D{SXqakRAMWb<
z_iNg}K<<K>vui>_kLSL8xmUyBg3-2~p1S+z?ZYqC*1yTvWE;g8!lv@lKHdKB6)jcO
zg*P0EH~+i&r^b8z!4IDzjBM2y^@>-o-}S3FzieBymygRw$CBptKF9XIyYuqf)hjZK
zj#nO=_1u9)LS^0ZT~+nR7do?5hlSajol;1Wj#172_Vn~`D?WL%FMsN`D4Jc6VOKt&
zVE)D2+<u`%#Er<>uy5Ykaq|vuO>~}K`p_xK%Uk)=6wRz^ri3*Y-dy0hsI${7&*u8B
z>g|tXB5$5I$)3LF9*=5uJ+ImRg#rl{^}!yJ8M$X)na`Z}e)1CC=c`xWXM<_foawc1
l&e{pjOl6oD4)FYE|1QJiwOg$DIs*d(gQu&X%Q~loCIAkVj+p=e

diff --git a/fastlane/metadata/android/en-US/changelogs/3.txt b/fastlane/metadata/android/en-US/changelogs/3.txt
new file mode 100644
index 0000000..e0f6ddf
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/3.txt
@@ -0,0 +1 @@
+End game management.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/3.txt b/fastlane/metadata/android/fr-FR/changelogs/3.txt
new file mode 100644
index 0000000..8c32891
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/3.txt
@@ -0,0 +1 @@
+Gestion de la fin de partie.
diff --git a/lib/cubit/game_cubit.dart b/lib/cubit/game_cubit.dart
index 6f80a61..ecc7b78 100644
--- a/lib/cubit/game_cubit.dart
+++ b/lib/cubit/game_cubit.dart
@@ -37,7 +37,7 @@ class GameCubit extends HydratedCubit<GameState> {
       currentPlayer: state.currentGame.currentPlayer,
       scores: state.currentGame.scores,
     );
-    game.dump();
+    // game.dump();
 
     updateState(game);
   }
@@ -108,6 +108,12 @@ class GameCubit extends HydratedCubit<GameState> {
 
     toggleCurrentPlayer();
 
+    if (!state.currentGame.canPlay()) {
+      printlog('user has no more move to play');
+      state.currentGame.isFinished = true;
+      refresh();
+    }
+
     state.currentGame.animationInProgress = false;
     refresh();
   }
@@ -139,17 +145,20 @@ class GameCubit extends HydratedCubit<GameState> {
 
     if (state.currentGame.isOpponentHouse(lastCellIndex)) {
       final int seedsCount = state.currentGame.board.cells[lastCellIndex];
-      printlog('found $seedsCount seed(s) on final house.');
+      printlog('found $seedsCount seed(s) on final house');
 
       if ([2, 3].contains(seedsCount)) {
-        printlog('ok will earn these seeds.');
+        printlog('-> ok will earn these seeds');
 
         state.currentGame.board.cells[lastCellIndex] = 0;
         state.currentGame.scores[state.currentGame.currentPlayer] += seedsCount;
         refresh();
 
         // (recursively) check previous cells
+        printlog('-> dispatch to previous cell');
         animateSeedsEarning(state.currentGame.getPreviousCellIndex(lastCellIndex));
+      } else {
+        printlog('-> nothing to do');
       }
     }
   }
diff --git a/lib/models/game/game.dart b/lib/models/game/game.dart
index df87774..74288db 100644
--- a/lib/models/game/game.dart
+++ b/lib/models/game/game.dart
@@ -124,6 +124,15 @@ class Game {
     return false;
   }
 
+  bool canPlay() {
+    for (int cellIndex = 0; cellIndex < board.cells.length; cellIndex++) {
+      if (isCurrentPlayerHouse(cellIndex) && isMoveAllowed(cellIndex)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   void dump() {
     printlog('');
     printlog('## Current game dump:');
diff --git a/lib/ui/widgets/game/game_board.dart b/lib/ui/widgets/game/game_board.dart
index 91715a8..d8273bf 100644
--- a/lib/ui/widgets/game/game_board.dart
+++ b/lib/ui/widgets/game/game_board.dart
@@ -39,7 +39,7 @@ class GameBoardWidget extends StatelessWidget {
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               GamePlayerWidget(
-                active: currentGame.currentPlayer == 0,
+                active: !currentGame.isFinished && currentGame.currentPlayer == 0,
               ),
               Container(
                 margin: const EdgeInsets.all(2),
@@ -95,7 +95,7 @@ class GameBoardWidget extends StatelessWidget {
                 ),
               ),
               GamePlayerWidget(
-                active: currentGame.currentPlayer == 1,
+                active: !currentGame.isFinished && currentGame.currentPlayer == 1,
               ),
             ],
           );
diff --git a/lib/ui/widgets/game/game_end.dart b/lib/ui/widgets/game/game_end.dart
index f94c8b8..12add5f 100644
--- a/lib/ui/widgets/game/game_end.dart
+++ b/lib/ui/widgets/game/game_end.dart
@@ -14,10 +14,25 @@ class GameEndWidget extends StatelessWidget {
       builder: (BuildContext context, GameState gameState) {
         final Game currentGame = gameState.currentGame;
 
-        const Image decorationImage = Image(
+        const Image imageWinner = Image(
           image: AssetImage('assets/ui/game_win.png'),
           fit: BoxFit.fill,
         );
+        const Image imageLoser = Image(
+          image: AssetImage('assets/ui/game_fail.png'),
+          fit: BoxFit.fill,
+        );
+        const Image imageDraw = Image(
+          image: AssetImage('assets/ui/game_draw.png'),
+          fit: BoxFit.fill,
+        );
+
+        final Image player1 = currentGame.scores[0] == currentGame.scores[1]
+            ? imageDraw
+            : (currentGame.scores[0] > currentGame.scores[1] ? imageWinner : imageLoser);
+        final Image player2 = currentGame.scores[0] == currentGame.scores[1]
+            ? imageDraw
+            : (currentGame.scores[1] > currentGame.scores[0] ? imageWinner : imageLoser);
 
         return Container(
           margin: const EdgeInsets.all(2),
@@ -27,18 +42,16 @@ class GameEndWidget extends StatelessWidget {
             children: [
               TableRow(
                 children: [
-                  const Column(
-                    children: [decorationImage],
+                  Column(
+                    children: [player1],
                   ),
                   Column(
                     children: [
-                      currentGame.animationInProgress
-                          ? decorationImage
-                          : const QuitGameButton()
+                      currentGame.animationInProgress ? imageWinner : const QuitGameButton()
                     ],
                   ),
-                  const Column(
-                    children: [decorationImage],
+                  Column(
+                    children: [player2],
                   ),
                 ],
               ),
diff --git a/pubspec.yaml b/pubspec.yaml
index 7d63e14..bf03338 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: Awale game
 
 publish_to: "none"
 
-version: 0.0.2+2
+version: 0.0.3+3
 
 environment:
   sdk: "^3.0.0"
diff --git a/resources/ui/images/game_draw.svg b/resources/ui/images/game_draw.svg
new file mode 100644
index 0000000..d988c49
--- /dev/null
+++ b/resources/ui/images/game_draw.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"/>
diff --git a/resources/ui/images/game_fail.svg b/resources/ui/images/game_fail.svg
index 2922fd7..d988c49 100644
--- a/resources/ui/images/game_fail.svg
+++ b/resources/ui/images/game_fail.svg
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x=".44662" y=".89101" width="92.772" height="91.894" ry="11.689" fill="#d11717" stroke="#fff" stroke-width=".238"/><path d="m71.624 59.304c3.5089 3.5089 3.5089 9.0561 0 12.565-1.6976 1.6976-3.9623 2.6034-6.2261 2.6034s-4.5275-0.90569-6.2261-2.6034l-12.452-12.452-12.452 12.452c-1.6976 1.6976-3.9623 2.6034-6.2261 2.6034s-4.5275-0.90569-6.2261-2.6034c-3.5089-3.5089-3.5089-9.0561 0-12.565l12.452-12.452-12.452-12.452c-3.5089-3.5089-3.5089-9.0561 0-12.565s9.0561-3.5089 12.565 0l12.452 12.452 12.452-12.452c3.5089-3.5089 9.0561-3.5089 12.565 0s3.5089 9.0561 0 12.565l-12.452 12.452z" fill="#e7e7e7" stroke-width=".20213"/></svg>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"/>
-- 
GitLab