From c3582b1f69b2e40fdbcfb79317ad3a67e7f9826e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Thu, 24 Jun 2021 11:45:39 +0200
Subject: [PATCH] Allow non square sub-blocks, add 3x2 game mode

---
 android/gradle.properties       |   4 +-
 assets/files/templates.json     |  38 ++++++++++
 assets/icons/size_2.png         | Bin 885 -> 0 bytes
 assets/icons/size_2x2.png       | Bin 0 -> 5580 bytes
 assets/icons/size_3.png         | Bin 1659 -> 0 bytes
 assets/icons/size_3x2.png       | Bin 0 -> 7616 bytes
 assets/icons/size_3x3.png       | Bin 0 -> 7436 bytes
 generator/batch.sh              |   8 +-
 generator/generate.py           |  76 +++++++++++--------
 icons/build_game_icons.sh       |   5 +-
 icons/size_2.svg                |   2 -
 icons/size_2x2.svg              |   2 +
 icons/size_3.svg                |   2 -
 icons/size_3x2.svg              |   2 +
 icons/size_3x3.svg              |   2 +
 lib/entities/cell.dart          |  13 ++--
 lib/layout/board.dart           |   6 +-
 lib/layout/game.dart            |   5 +-
 lib/layout/parameters.dart      |   6 +-
 lib/provider/data.dart          |  16 ++--
 lib/utils/board_utils.dart      | 125 ++++++++++++++++++--------------
 lib/utils/game_utils.dart       |   3 +-
 lib/utils/random_pick_grid.dart |  10 +--
 23 files changed, 200 insertions(+), 125 deletions(-)
 delete mode 100644 assets/icons/size_2.png
 create mode 100644 assets/icons/size_2x2.png
 delete mode 100644 assets/icons/size_3.png
 create mode 100644 assets/icons/size_3x2.png
 create mode 100644 assets/icons/size_3x3.png
 delete mode 100644 icons/size_2.svg
 create mode 100644 icons/size_2x2.svg
 delete mode 100644 icons/size_3.svg
 create mode 100644 icons/size_3x2.svg
 create mode 100644 icons/size_3x3.svg

diff --git a/android/gradle.properties b/android/gradle.properties
index 81949df..957c40b 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.14
-app.versionCode=14
+app.versionName=0.0.15
+app.versionCode=15
diff --git a/assets/files/templates.json b/assets/files/templates.json
index cd7ae73..4f5a298 100644
--- a/assets/files/templates.json
+++ b/assets/files/templates.json
@@ -38,6 +38,44 @@
         "0410200010000200"
       ]
     },
+    "3x2": {
+      "easy": [
+        "000142214003050361006500503006000405",
+        "420000000000241030356410602040014603",
+        "540010030050120405003162360521210643",
+        "014300023160005423342516406230230005",
+        "200061004530000206006015045120302050",
+        "651400230600460201020004500103000006",
+        "010602206051160305523004640013001000",
+        "500004042060010032024650460320003046",
+        "060123102500340050605341006005450610",
+        "560034004002000041105263600400050306"
+      ],
+      "medium": [
+        "005000600400300005200004020000010060",
+        "000060020051306040000005000000040020",
+        "023010100060500300030100000602005001",
+        "000306500002400000230000600030010640",
+        "000030006405030650002300000000160020",
+        "050100460000030020120603045000000305",
+        "063010410003000460645000030000100000",
+        "000000205004100000023010060001530040",
+        "620304000000500063400010003100040036",
+        "000120510600300000050301060010005000"
+      ],
+      "hard": [
+        "015000000400200000000014000000156300",
+        "003160000050006004300015040200231000",
+        "060000002000000002000300004010100650",
+        "002501500400605200000060000000020600",
+        "030100002600000420021000053000000030",
+        "103204205100006005000003500000600002",
+        "000200060300500002012004000003040100",
+        "052400000001000050005006040032020000",
+        "200160060023000600000002050430004000",
+        "400000060000010400006002000205050046"
+      ]
+    },
     "3x3": {
       "easy": [
         "004210007090083010000500200007050831910600740400000000006100000801007450050300000",
diff --git a/assets/icons/size_2.png b/assets/icons/size_2.png
deleted file mode 100644
index ad699660fc4d991fb370035ed828b50d0722452c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 885
zcmeAS@N?(olHy`uVBq!ia0y~yU^oE69Lx+145>_WOc@v$I14-?iy0VXB0!k&?2PAU
z7#J8NOI#yLg7ec#$`gxH8OqDc^)mCai<1)zQuXqS(r3T3kz!zA_#EI9;>y6lkoEt6
z`v3pg|Nm$H|Cfb<7#J8B7#SIvm>8LvnOInuSXr6a*qGVbSvWaaxVTukxmkI5Sb2Hb
z`1siP`Pl^o*aZdIg@ic8#JD6RxTU0c6%_as75S8u_*GN{H8cb@HHEabg>-a8jf})h
zO~oxNB&@6?t*xc(?BqN=6nuQtVq(<e;?(2gHItLIQc|?i(zMglbuu$`va*b;t4(Ta
z%^Dlbni|cTo2<IKto!?HCrxykKhJsL0@r0ry|--k*}lzh_pXrBr$W!3iM)0-_QC!5
zCy(QwK1q1?H0|q`jGsTU{{LIzR@=|Oz`$J+<QL4KsinPR=dRsfzkUDv<C8H11LGS{
z7srr_TW{~2^kZ_AaDBLlaiL(KgWADLCxP@i>8zqIzyHoZ=DTs_k~$}z8>#1F=P&tr
zXwib%3qnjLa>>MI9Shca#m;yBdx%m&RpHa!ydJ9#d}IWLAp--$A(kI6+G_4AGc4b%
zcpoe_hhdHR+vv+@yDsENU)SY)J1@`3>GGK#&I%E}{ndA4xX!L-%;0#tJa5_(;q5$N
z9q0r*LwW7*b*05hCg<4}=xuqwYbA&8{v&ToLF#6xC2Y)!k2Bvnt5)^#uFp=<SAC;0
zvR(?zKhpfrQEl!KQIH}`Ji|sIe2f0_*{lmsN;g<8)a6lLsQIY|NnOKA#=NR;u`i!R
zWX$V%eXaGIuX*aim#sh3r`IfHK~e`}KDf_d7X2;vMOtV^8LvZRhV-tJ9KP9i?7N?Q
zvjVC4!&Pu`<9i?TcBkU(m~!uo_>y3OS$>WELLf;DJi{j8|DAmgjn~fIR?E(o5Sh_m
zGFfz1*|giQK}rpH9lk3*`7Om*kO$&2FfcUOv;N52|8L2xLTQ2Ed6)AYjTTK2FQ4|{
axY8^3BF&n=rM@w|Af=wJelF{r5}E*z<T0@T

diff --git a/assets/icons/size_2x2.png b/assets/icons/size_2x2.png
new file mode 100644
index 0000000000000000000000000000000000000000..90a48baea5a702764515bfa638fcc2e154fbc0e1
GIT binary patch
literal 5580
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
G&;$Vf;ps*I

literal 0
HcmV?d00001

diff --git a/assets/icons/size_3.png b/assets/icons/size_3.png
deleted file mode 100644
index 0d20bb1e00f264f617ca1154d3488e946d13f936..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1659
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

diff --git a/assets/icons/size_3x2.png b/assets/icons/size_3x2.png
new file mode 100644
index 0000000000000000000000000000000000000000..6c427f089bc80e4e0433d583289330e8f6b700b4
GIT binary patch
literal 7616
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
KxvX<aXaWEYfzRgv

literal 0
HcmV?d00001

diff --git a/assets/icons/size_3x3.png b/assets/icons/size_3x3.png
new file mode 100644
index 0000000000000000000000000000000000000000..7b4c28cb3295725e9a98d9d449ebaf7dbcbb60ae
GIT binary patch
literal 7436
zcmeAS@N?(olHy`uVBq!ia0y~yU^oE69Bd2>3_*8t*cliYI14-?iy0VXB0!k&?2PAU
z7#J8NOI#yLg7ec#$`gxH8OqDc^)mCai<1)zQuXqS(r3T3kz!zwnd#}`7*cWT?cB;K
zAxEzssL$crp})e>SA?ZEu&FRUAiza%W*sk|gaEVD(G`W=g}zE&P10UM_9ha^F+W@y
zS$+sCl9|!K;l?WN;=yt-(2*rYG%{`F`~GzY&A-0-TK)Hx?|GN^bBg`_gnoTn`!qbZ
z^!2@H1}~Q<(K?qnm6#ejIv5m`KIO7MNPTdo#puk1udU5``*X~{+<Uno+s`F^P05A3
z=NGNd=XyIo|Aoxs1=%4zoDVHu+)sERHOuMue6x~$&lkMDrNJ;y_2+#D=j&RRe%{V{
zan|a^EE&Ter)5gEZ-0?J+39z>gq3{Bh0<ys2EL*T`>$On_2hahpY>wS;{~sM7#$b{
z7+4r6pne=<-VjyqC={9W;?~0jr}abI?j7aZb<LIMpBekz&$_>!Exk}@e59had0l@J
z!-ux!e_YPj*)_NP7j}NG#vc1#k<(BK77$5H8yw`VCY?}mzCN9A*Po<!+Q+S4{8CtC
ze9iiWT;|2^9$atZ^Ipt(y<oM@v6hM(j{n2k)^TcX`7i4HT%B*%JTd(V6^%!@RTwxJ
zm>L)qs6u@>%lsfT!NIBW&V{Xx<qfOf7<}m~xbQXX$b<D|7iu@V-tX1i^1s&kxd?l#
z{t<=;QtW?c^TzfsyYP>bMfmOHS5jR|T)H|q7$9EcJYZHk!BgqkzxB5qr^ov=n_IrP
zC3jIWly6tA>-K9)FVubJ`7*V6ovxwU5plj>t9fH*2WRY`nGyeRL3VRR<G#Cb3vN@z
zd-n?%j=kjbP`WPcqi>_ZYRD+@WI=Y+kq6VQU)Y^p^nQuRE&JOSEH61;&rfD3SkwGZ
zpJQ40u5JGlo8C*PUww)kV@eEg&oL+{DKT_()MPVObjL7WRWa&I@SSlxcmmhy+^@Nu
zsf8}-Yl=5~R_xx#9+dGv$oaW8->$eWL&du13+}J6{^G>-R^Pa!?#Y7eDJ@PO8Z9kO
zlt<zLbIFG9rR?exSGKLw1*NApXaAB5TTPNam|MK4JGAKiN0D3cejD`sf?_u(F&JEO
z-2ZdQ%PAta?5|(gdC2j)go>h@iwlE*pdf>biw}d{<@R+dn@(KVde?D!{3@Qk+%hF=
zJ74sy<=gc<>dRTrg@0djT+`R}*6>dD=?Ito@_xe{&C@ceJD<*(7IMAjBU7ii#~uf&
zB}-7^zHh^z_QKIyX}?Ly+QJJ@r{}iaTivjYGu7?LgZeiK&u@y=rZ2tl&k~#ts}$H6
z)Gc3_PcF~%S@^eK!s@x@i&x#qX_G-gi6LP3tEk^CMXR3*+_7Ud<Ubg0{X(nzMUTHs
zN%`g%*4C}xW?xmCS8&19=2(lxS;zgA9Q!O=zxA7xoGZU@)&I_dM{J_zD~QQ=0m~Vt
zI8Bz@(9hnU`cQ(u@B4!v_b#k6-=f*Nm!%<JjbZM>O#U0o)n(>2CTAbJ*SyX4;Rm4`
zkEIzMgn!sDFHe1NOvmQsL2bD;Umj@lhw$8-*m(Y2%c{qYvYf9R0;&%)FfK@BzQA&&
zZh>E;VPwUv=ADv1beN-)`~H^khgBHt7T$ANE<`)vtdteQ?xrl}S0Mqm3$4<UC!eU6
z<2ilcB$LBoh6Um>m-x2L;ajz&@0cy~E14gcnib_rats(!9$s1ZA<gry?~j0!hYs<?
z+!c=EVmQivpt;y)#v8|_;eS5X8#6b1B~GtmT%i6(f%$(&c7f)KgA3NNmuj!r?O@CB
z%JJ`f{)S!bS9E{f|Ejsh*zRM(1Az=3hAXxVdmp&$UE6DFSNnCwJ%(3i0nR$f_2w&P
zJH{@2?!}nAUxj<AEAs+lldli-_J(hkDm7fOaKW+0D)uW<0aq7<G=5@T(Yhdx#nh?X
z&n4YQn^)e2@ql2%yA7+^`JYCA{N1=q{K|bt-3!SPFLs2#w)`x&!gE1evy_PKx5w27
z?DQCNu1!`5ndMx$d_waZ*I7?07nG@Fl*B~xy{ZhD-d=KqHDG7{JIB<^|8xbL;~8sa
z1lVnRp<R9<T>07K%hEC>wSvqIpEhjF=aesR%-v@9p7|C3f_to?k?xP<c(XWHq&xgo
zNqKX=xy!aF@$ELVH9brU>$k9!=AF3q>^!Gu`9!aP&0qXiXI^f-CEVztwTXSjXXm<?
z^BK3UJdwPg`HD%v^vIl7d|B(a7$1sy@`9`8X6^zz&7#M-b3cZ>bBH;;O>V)rDJN&2
zdh$L`^0(pwyY<gE-sj3%a&+70uT68g7|s^GTYg}=O=P=$x#ttp(+^kPzWy(HBFm+i
z?+YJR1}6*8d-=+1S@Wyh8<l1&j%6|wY+A}3m*dd;{j~Kjok!chSIj)oxkPY<pIiJl
zHq*_GeScR^i#=etjzK0Z@~67l1-=y%jk?eNKGmWZ(YHmXCY875je3OM`EMRv4#j)>
zziG?NoU~BBvC8%TBp+5&_A9GItRE#Fe&=VjkbBZyUGrV%mpwTdxoWPse$%h^d%M>8
zUJNeTp7`C<lkvyIg)gE4Zp-xi=DPA@!sOlmt(P^gDtgoL^_KI)>$>cZeiU_GEZ=T1
z@4H!}6z{7`Hp%sq?;YDQPd7~Bd1Fu9na2ztR_@c8wMYESi64(DH~n(bS{W#RZ1<5{
zn&nF$L{(q9a8vP@T!OdnZ{d!$Pfqc$*P14|Md+1Y*lKa?$^0^gGiKlaKIMD7!Jz;C
zJ+<%I@B2>Q_-|Js7U8ntT-FcY0<nKj!apo{{A9m{<C^38vies}HOnpZ6>R>W$h?PB
z&-<g=k8c*{2j%{py`R5W=2$}GQEOrMcV%~2b$I5*pGs<XDrvrJbK^<;-|6ZmDa9vF
z&2KF?F31;K_wm7Vxt<RRJAc0a_iBgGjOi(7SsL~*$S}*=toU&M-FnX(-?I;Gw^?6p
zaHV;E>cd?;fBN~RuK)V}-@6LWTl>G6Wn>4xkl}9NiOI@ypCt7uXT!&6qn%u_jr+A1
z&SYD7P4stF`+NDg8Rjpd`49Zu8Sr@SU(-7a-|LEpyxv@p=wakpJlA@|=llExcewr@
z`|;1LQ2TJD!M*<nS90?HxU}i($pfx}%~wt|PyaiA=Ccc&=OypgcQ8y4ZxE_Ddq2Kd
zCagaBb#N$CY!XZ4xzF|g_sbmnXPEq^en$0r1$%~D9bccFzqoYP3iYki(=vPh{yg)5
z>%;jO3%A++nJ@kD0_S8NX+B{Fr`z{K(jU!Cw)beawPAfVf5EiIRT>-a+e%0q?@w4D
znLFXyyT>d$jD;HF3aaijd+7&Uf5H68B4EArM#b;!;s5s)S}kOW`fdL`yWMX_&W(Z{
zh37AxQfEJOil@X^Y59QzVQu>^Cpet_KmY7rvB?|_Vs>-e58hZ}wykmh46|QPCou7?
z-0K+2{z@^Rp4s&Nho|=w|NLHY_5SmkpNUb?8!oo-svlaf%y{B}?7Ep&e@iCB*ef5u
zKIucw-^-kzt?jE<JFE8?=2+i|__#~Vuz98U7mbo{=8ZF-iyYh*>?k|CX`Z*kUoDBg
zPp;`1Qo;@2>S_<m9IFetz*|?l#@IoO@51V9zH&BC57y|b@a>skb8km;9Mkci_SN&9
z)q4!y+_?XuVee~$_N$XF@A~1D5yrtF`*88DZL4>`U-W|gf+6$s$^vgTxAcdxx3{fu
zm>KBMm1_P!UA|bN`m@^(+dnFWZV~Ajvl<s0U%1|!XvP0!F%w(8&mF%L2lD^UmwkJI
zGyG^lvs~aEn`^JRBRKp{T*)nDeA;NGp``rAD<h0acGHFX&A)9cJi~K4tiRQ3Ff;`I
zJMUM<(fK03LVosbd7~2VuI~x&g)Bb1RBTgTVO(m|b@Y9Gx=(Gc?Tt78-w3sHTRc|E
zDZat@!KC|a{e_cqdPX)Y%45a8b-!v4x^c9bHEl&hx9(w`+&2#<h|F*OyQyFs`}OJ%
zF5)X*WXk{6PO`GEd-8wl$)>2e1#j+i-7@G-y2g4-_F9U<>f-j})dhY%d_U%~%g^96
zzpD9jVSlq~BEy?mx4A-QamueN)C}Fl(O{@4*SS%E$8_?ka4R+5y9qZ6`_?^t93*<^
zNAztE_DixnuS#aTICw<JLXXYozIlCU%(wrCoAx`I2c4h#Q0i;T-@|&2Mg}*UO_xpA
zeEBL~?u&Eyd(n?BmmGKAJ`ok&$EoR}u}_+1ff4s{mkOt>x4UCM>$|b;HA>8EUK!r@
zn#b2WG5$9Du7i2M*6cj#v)PyH&+lnY(N*uR$}`v|*5{rHm(#iQ`^3jxTaJm{zV}hJ
z{p!2v2j?Hye|!bk$Ay)`ccrh?2Q?&QY^c5bIfm`5|LgD#Y1R{X?{$f-HCYsQcPjhr
z%^NN>Yg*mQ=sUY}Qt6I{+lyj9x19@IInC9Rso~|lu1|*kMHYW-k|G(s9&}hRyx1h4
z|I@yHD&NyG#)PG+!Me=i5!>vXFWvc-!(e*h$Gyv4G16Nm>|PoaU@Y^fUg!Co-bf1t
zJqF|AV$+F#E?(GbXFku;QYf$YGGq8_jzdc({}1dwcR6v(wvT5y7{VBDUMna)rt$aF
zagjRKe?mUD{+CRT$?y<6A;)H(Qq!0*@32$AWqIe%J8Ya&CLESASe)z5aFfq+ed3cF
z_aAI{y7r1{<(>qiGmGthE9E!6_Tf8q`Gb6RQMy&jfjqvCMRVp{xc5G?<ZKa3!e&*g
zO>6c4Z`-WOc~n)UB52F$%^IKXc64uMcQ{*m<JsEl)AQplyu4T-cgpUH!8`q53wGJD
z`k&sdxV7=zmF;^ybL|cWF{dwGyf#>8X>{4fC-<i{{kmZ&erU~v!W`Sw=`+9U=x6*k
zTVn9-Ki5i$@~k~w0!Nt_<a)8k6vx}@q@-FNF8p+TO7qKUMOg`|E9OgE`ER`Aw!32f
zw&;D2b9SHJtWmTj@${W3MW^b8jlL~EGXD=FgVsq~kBKg25mVm(`QLB$ZQFV)le+Fc
zpFJ8&nEe`7sqGYh=DV`%MNige<KIv3X$EB8^=aSX8hrQHpOY7^8&Buo8#}$OXO_Ti
znIl)WGT*p$aYuaQgA3bwt!x&Bd)zN=Ipy~7Tkd*u{R!;Kf7|xW{t#fU8&~&IjKA(a
zH=kjSPl!x-{Ijb?mvt3Nx4$^Iw%_~T+nVmv#@yFmEW2`=+fc6O>+Q)ZyEiz^&-~@y
z|JRMb?Wc|Xzx}_8o6{0{?qA>+UiT-}>OgLS&GuVn{CSd}N>6@qVVL41yjkSO(>~AN
z^V^=B>MOsn^IXx1a|gN|7FV$)?7F{fD`)t>Osg+-4tqBKztpTP&BGw)^I3YwtwPqd
z*R)Tn$bP+UUZ3uB{e7RRUjMvCXWNM9*Q?hjOV2ZSv*+f+n!vTr<~=9>&)g_<O`IYB
z_uE_34&BhdTFJ3r?UQcf$E6n*DKZ3TU(L<tVpsh9?R#z!e@@C<*^gn~Gp30!)Xuzq
z`pWPADR&l$zif^TiWP2tyLQ_X`77cKPyflh-?I8(F7sEm71o@!t{GwFH#YBMjCi-+
zBw+f}k9Jp9uN42%vL^cxL&HDSiaU2U>z8l%>bf>P=ainmemSQrGvfpA|JOF^9j}|H
zw=Rt_G3(7Lfl`(OZuNaH(*n9nBln1Jt*_a3&fItLtAeFRrG*|Br9}3)nVBD+vi|bA
z<4el=3U2&*v%!7#zURMht`BD@$vEkEd)@Va|BqVTOW(BKB(1V*KgZ#>+z&Q?WopnX
z4_bXH#_asQx9V0^hP_o2{iDBZFJf4r7InGiQ*nsw`kX>-`HByrY<+x&dtWeoX?j1S
zFzzSc`svx?-;ar$<D52Q!>PTmm>YyF3_O<w$sdoHF{^LKbs_fqCm0!c50)<5yI#EV
z)A`N%D)y(7%Pulr;9sbIN_+miLwW~n#7kE3Gt@lX(D}r_@AjfzvFnl9?hFlXkuy?`
zZC#^x>B;{?aizJd&Og1Wz@X7+9DD3vz3lJIsYji6#M?3yv@I>vwyE$-w~Jk!x}r~z
z|H;8!YRi23;yAhLR5yu4%~bvS?#SLvrE}u9?r!?~vyxLrBC+Tq<Aun^WozXtKlre{
zJ9pq}<PJUV@0A~x@iJXE=X9IAJ*Fyfn}h1E8`oI)*PT7|JvpSc;`AMBz2X-wYpYtn
zO+Rz*svtw{j`wdIL!+igddf9^Sa54v^aTNi4-bm?!>T_tv4>Y(FiXm=Y-9g#*enox
zuP-9M;-uahS@F>C3?<EXy%u^lu73SaZqLN9)~uzI@BID6=L-s?zoiph#hyLddc?t2
z<non8%mG}x`A`0@*lBw6UUU8Omnl1rzu3(DN>P2sgZ=j|EIV>Su<RqxS+!4pSGX{|
zh~E*lEB%Tf!}=TFPt{6kF?fo;<PyC4@5~Ne%{$w#c<lbq#=y{LuEcp-M!)CGjKXk+
zl69X?ZCNFGWFmVr!y3(A^TPkx3>WsV3I6kT&if1L?*)GqBpqgZkg(Y5(Bi&_LUpmR
zmn@lkOuISOuTN&!$MW^E0*k(TMZ>?>3?~kSX0|R|&w0MvPrgBI=a0`@BX?|g_OW~3
zhh`P8XsJ-<cSUn-mTu)vwPZ{PGx}EI<F#>Kv+f7J1sV)5Hiol5-J`qM_D3=spYM*X
zHV5zTYnLhZ__OO=5$gh$sPu<Ce`g$<u=(LtzbA1o_%!>=lPCFQB;DC@?}<g>AJ*#g
z<)Ch3l3RP9&L`I!^K~l)R0~pKnG9H@(jQ#VnKQM~QSQ#<lfGYeic8!xxPRljx6wD-
zhr81jZdy_sns{=;X2uPn`LSW9jpx5NZC#sKYklL2;I=tzw|6}|bzd}Q{ih`{Zs(qJ
zx}^5364d+mc}=0RkAZSt=oFKt(76e__t!QDYs{VGCKDij<D$i#Z)Xh|BJPUV-Iu;5
z$MgF3;bo7DlK20OS)t)+@J;sNYL(>us{=LOnjJrVVM6tS_0sp<)F+j%Z)RHaT=k54
zuGfc$Hq$>O8)w>e`nt26p11laUzx7|P2H-HCNtTU+gZi09K11q>W2B{#$R|!Uo01W
zc-86A)b$!mHe58l6=7Vu(Y49%#^DQv{f|=$b!TpBKey5Mb-}j4^zA#32=;R4SuVQg
z#O<+L<k-IczMj8xH(u58j98FR@4Yc;`l|}Xz=QGi5A}|$o@(#$U#3^#J6rh7b;oyH
z>$q8|vxLo0v1rD^$C>SZGtyrCs%zY4a&4aSXP=;nP2R-@C+D}U-NsToH~PVn+q%bg
zq?c}aCR=5+Z$Y-D?zNXQ>Sn*|-dED|b@h}mi!(buT$-?TU&*=35BqjL^1F7g_Y>3O
zd-o0ZePPm253kHgh<Tav#`3vkNmHcmFY9T4^ILR-&%|3#*I9Q{lkbBTlm4d_=XRRk
z{F5s&J^#?$+?s!kbC(<XKQ|C(T2YyJomWiE=-q(@a&B8+@XP!<-otTk`Umw%>-=7)
zFFzHx<wW;u)(iSmuXJs@Gi#CVS?<%E?^2Ha+0l}<e!ENYx63D$JWKtyAK{QZKj~Sm
z%6pB+pZzV5#l_0lXwQvn=>946KYe|Hhm=vS=1FnxCGsm)e_3CoCvKhG+#DnqwCPYu
zqwKuK^MB^oUOU*w`jIa!jA7T|d2%|&^6!c{FY;->c>2m~ulb7NP|Yn}%m?O8+tjMJ
z^R}4z+uw!vI!_<i_>afw`q8wqe;f?2tq%(Sk*_#cs45}xrlY>Ppk|(Rn_gPQL5Jfy
zil5hRQ07|A{UyA3X<6rQ{q7s-`o0eXa$n35VP_~>{a8A4k6>)@%wNY3nw>i>&b#LE
zs%ta#(!>SYpV;?D$e*-6{lD>F-{kytf3I!2)%-GYhc5SD;|u!C+tU)K<p%9}`{D0=
z$(0o|3;M4ZoqqD&r#j8*#-?i=r>_OQF6@ZE>bva5(?W(9T;Ve`yYy0h;x;wMJv}&u
z=gyqQx;VY!H-5&ywl8ZqB-H-?|A8RY^_g>O7&iBGW?Q`a%o&@#H)w_OFOLl+No(dL
z%>A%QYpu9;ZsJZk9qmTGw7!qoFQ0SOS2FPQGc9m^*H*nV@{HNp>zR*Ex%R1=h_1Nr
zCeFdf`as6`SnbNihL^Xlx5#7X@kmtCF$z1}^X=(zMu+_^J3nupZW-1*J1vqkTkgWQ
z9;sh?c^7A$;<(OYYxuM`sl}<{!()@xN#U<|x$fnb_<eed_{G#W@%*puUR*R`P6GeG
z^EG=8ZC!9RYp+twoaG;<H&q4QzoT{h^YQZ>d&J~c>vWxqTeX#U_VXL>>MFCozhGGq
zmA8Mt<+l2jsh4CW^~F{Mvc(zaKhTza8@aH)_qWR(!(P9{dAXbBwC*}|r0LY6FKuQ2
z7P*-UR%Tv(8@WV#_1*=kQY%_DpI!;ej_&<?zfa7N;RSE*ncAO^`?lT5Eo7OowYsDr
za&5cwwWWK$o@uzH?q)Ej@5ma_u7A%(l4pp$U@kj*!~c3@N#<Ey@A~yO)WbE`Z&)QD
z`D3MLX6@Ajg(U}9DnEGJaW(&@Kt_(-k@ZC}6PMlEZkK*TN%w5?17%I0w&;$pHdzW%
zSDJ61wX0dz*k5hBqW!JlO7RI>Ocu@j68L!ix{L<dfR*9dr_aBRND?{z^+9;%v+wIR
z<$T{%5I;|4LhxCoByXADPmH^*H#ze#m`pIX@wV^^WtRCZD^|XJ+QeO+CmCLF>gK*X
zX<bq~tL+k_^jFrYOPSO7TAl?mykVYS<u>E<=f2ewmnOVc%JtqCec}1#8a2~1vXu!v
zH4OaUzCDmVFEn%KO2*#5Qg6N{*v_~iIm?Ri!EWB#%V7s!FP-u&PfvJl&joYld)Jm;
zJjw3x_>SVrYft{SK0bK<lSizpzJ=j2-xmv?-9A|y^g{izYQ;Xjh90kulZP17rnb!z
znzs2><)iSIx@q;lmp;---dMPrZ>{1CnQup)zES#b6875Q`t3t|xi0sJpK@ljxb`C_
zUY6n6CkD6q5A43YV@gVF`(^(-_|EHBxAQvv`(_G;ajnhS-7rgi?mdl9N)ev#8u!dT
zlz-*;)I;ywjPIOY{JQp`fxe1yhQW&TFZ;Ic>Qk%T$(JuX=l*n?J3-wixE!=kKVNQj
ztD-vKx%JWw-i$9BbpMuqwY{5m{om#v$If18xG?2}_QFUuIquh=vmJX2dnWY0y3YUA
z@z16Yh3ii}yT`mul%s<sVP=~`P}Jem&kwfMOqXQ-8u!t%cHvf+`I3+RdF5Q4`%}Mm
z;wOcR@0;iH&*pF5B(U4w)Ox|pb796`zg$=3_FNKQ@N|6^Yw!u%8?w>24#s?TsPp7X
zYV-WUaP`w`J4tcVZ}*!e?<N+9Onshs>*&v2^LD)EiV)fU!mDBZOM{QqZxvP2u08zK
zT-?8)<>tR45e8QEjxF93oNh+Pm+@Zv#I0-o;=kR5i2jAFNj80pJ}h_eU(qb$u>Qm8
z<pGwfIlf)B(Z0QcVfU;T|K3eZc*FjpaNjBOZ`WV{e;f3>H8E~y0K2)F-?iiK-XAc#
zC}|ekZ4$A}fA`wI2I87)yA$G{KVe>cp;P+ktJ7ti#oKNR*7)y~xWszpp~Zgox$hRA
zsD3qdVey$Sr<_z5Prli&7VvD>1NRNqudf{3HN`gQ#pOQN4WDE7&e&42p*Y`GFSf@^
nF4MDf-Lry_FS%toKkIkO$+UW2cv{ZDz`)??>gTe~DWM4f82|02

literal 0
HcmV?d00001

diff --git a/generator/batch.sh b/generator/batch.sh
index db34718..3a08b05 100755
--- a/generator/batch.sh
+++ b/generator/batch.sh
@@ -2,16 +2,16 @@
 
 CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
 
-ALLOWED_SIZE_VALUES="2 3"
+ALLOWED_BLOCK_SIZE_VALUES="2x2 3x2 3x3"
 ALLOWED_DIFFICULTY_VALUES="easy medium hard"
 GRIDS_COUNT=10
 
-for SIZE in ${ALLOWED_SIZE_VALUES}; do
-  echo "Size: ${SIZE}x${SIZE}"
+for BLOCK_SIZE in ${ALLOWED_BLOCK_SIZE_VALUES}; do
+  echo "Block size: ${BLOCK_SIZE}"
   for DIFFICULTY in ${ALLOWED_DIFFICULTY_VALUES}; do
     echo "Difficulty: ${DIFFICULTY}"
     for i in $(seq ${GRIDS_COUNT}); do
-      python ${CURRENT_DIR}/generate.py ${SIZE} ${DIFFICULTY} | tail -n 1
+      python ${CURRENT_DIR}/generate.py ${BLOCK_SIZE} ${DIFFICULTY} | tail -n 1
     done
   done
 done
diff --git a/generator/generate.py b/generator/generate.py
index 6277232..4551ab8 100644
--- a/generator/generate.py
+++ b/generator/generate.py
@@ -1,20 +1,28 @@
+#!/usr/bin/python
+# -*- coding: iso-8859-15 -*-
+
 import sys
+import math
 from random import randint, shuffle
 
 if (len(sys.argv) != 3):
-  print('Usage: generate.py size difficulty')
-  print('size: [2|3]')
+  print('Usage: generate.py block-size difficulty')
+  print('block-size: [2x2|3x2|3x3]')
   print('difficulty: [easy|medium|hard]')
   exit()
 
-size, difficulty = sys.argv[1], sys.argv[2]
-
-size = int(size)
+blocksize, difficulty = sys.argv[1], sys.argv[2]
 
-if not size in [2, 3]:
+if not blocksize in ['2x2', '3x2', '3x3']:
   print('wrong size given')
   exit()
 
+splitted_blocksize = blocksize.split('x')
+size_horizontal = int(splitted_blocksize[0])
+size_vertical = int(splitted_blocksize[1])
+
+boardSize = size_horizontal * size_vertical
+
 if not difficulty in ['easy', 'medium', 'hard']:
   print('wrong difficulty given')
   exit()
@@ -30,13 +38,22 @@ if difficulty == 'hard':
 
 # draw grid (array style)
 def drawGrid(grid):
-  for row in range(len(grid)):
-    for col in range(len(grid[row])):
+  gridVerticalSize = len(grid)
+  gridHorizontalSize = len(grid[0])
+  horizontalLineLength = ((size_horizontal + 1) * size_vertical) + 1
+
+  for row in range(gridHorizontalSize):
+    if ((row % size_vertical) == 0):
+      sys.stdout.write(('═' * horizontalLineLength) + '\n')
+    for col in range(gridVerticalSize):
+      if ((col % size_horizontal) == 0):
+        sys.stdout.write('║')
       if grid[row][col] != 0:
         sys.stdout.write(str(grid[row][col]))
       else:
         sys.stdout.write(' ')
-    sys.stdout.write('\n')
+    sys.stdout.write('║\n')
+  sys.stdout.write(('═' * horizontalLineLength) + '\n')
   sys.stdout.write('\n')
 
 # draw grid (inline style)
@@ -47,12 +64,12 @@ def drawGridInline(grid):
   sys.stdout.write('\n')
 
 #initialise empty grid
-def generateEmptyGrid(size):
+def generateEmptyGrid(boardSize):
   emptyGrid = []
-  for i in range(size * size):
+  for row in range(boardSize):
     emptyGrid.append([])
-    for j in range(size * size):
-      emptyGrid[i].append(0)
+    for col in range(boardSize):
+      emptyGrid[row].append(0)
   return emptyGrid
 
 #A check if the grid is full
@@ -97,9 +114,9 @@ def solveGrid(grid):
 
           if not foundInColumn:
             # Get sub-square
-            blockColFrom = size * int(col / size)
-            blockRowFrom = size * int(row / size)
-            square = [grid[i][blockColFrom:blockColFrom + size] for i in range(blockRowFrom, blockRowFrom + size)]
+            blockColFrom = size_horizontal * int(col / size_horizontal)
+            blockRowFrom = size_vertical * int(row / size_vertical)
+            square = [grid[i][blockColFrom:blockColFrom + size_horizontal] for i in range(blockRowFrom, blockRowFrom + size_vertical)]
 
             #Check that this value has not already be used on this sub square
             if not any(value in squareLine for squareLine in square):
@@ -115,16 +132,16 @@ def solveGrid(grid):
 
 #A backtracking/recursive function to check all possible combinations of numbers until a solution is found
 def fillGrid(grid):
-  gridSize = len(grid)
+  boardSize = len(grid)
   cellsCount = len(grid) * len(grid[0])
-  numberList = [(value + 1) for value in range(gridSize)]
+  numberList = [(value + 1) for value in range(boardSize)]
 
   global solutionsCount
 
   #Find next empty cell
   for i in range(0, cellsCount):
-    row = i // gridSize
-    col = i % gridSize
+    row = i // boardSize
+    col = i % boardSize
     if grid[row][col] == 0:
       shuffle(numberList)
       for value in numberList:
@@ -132,15 +149,15 @@ def fillGrid(grid):
         if not(value in grid[row]):
           #Check that this value has not already be used on this column
           foundInColumn = False
-          for r in range(0, gridSize):
+          for r in range(0, boardSize):
             if (value == grid[r][col]):
               foundInColumn = True
 
           if not foundInColumn:
             # Get sub-square
-            blockColFrom = size * int(col / size)
-            blockRowFrom = size * int(row / size)
-            square = [grid[i][blockColFrom:blockColFrom + size] for i in range(blockRowFrom, blockRowFrom + size)]
+            blockColFrom = size_horizontal * int(col / size_horizontal)
+            blockRowFrom = size_vertical * int(row / size_vertical)
+            square = [grid[i][blockColFrom:blockColFrom + size_horizontal] for i in range(blockRowFrom, blockRowFrom + size_vertical)]
 
             #Check that this value has not already be used on this sub square
             if not any(value in squareLine for squareLine in square):
@@ -155,7 +172,6 @@ def fillGrid(grid):
 
 solutionsCount = 1
 def computeResolvableGrid(grid, wantedAttempts):
-  gridSize = size * size
   global solutionsCount
 
   # A higher number of attempts will end up removing more numbers from the grid
@@ -165,11 +181,11 @@ def computeResolvableGrid(grid, wantedAttempts):
   attempts = wantedAttempts
   while attempts > 0:
     # Select a random cell that is not already empty
-    row = randint(0, gridSize - 1)
-    col = randint(0, gridSize - 1)
+    row = randint(0, boardSize - 1)
+    col = randint(0, boardSize - 1)
     while grid[row][col] == 0:
-      row = randint(0, gridSize - 1)
-      col = randint(0, gridSize - 1)
+      row = randint(0, boardSize - 1)
+      col = randint(0, boardSize - 1)
 
     # Remove value in this random cell
     savedCellValue = grid[row][col]
@@ -183,7 +199,7 @@ def computeResolvableGrid(grid, wantedAttempts):
       grid[row][col] = savedCellValue
       attempts -= 1
 
-grid = generateEmptyGrid(size)
+grid = generateEmptyGrid(boardSize)
 
 sys.stdout.write('Solved grid:\n')
 fillGrid(grid)
diff --git a/icons/build_game_icons.sh b/icons/build_game_icons.sh
index 41dc2c4..819a80e 100755
--- a/icons/build_game_icons.sh
+++ b/icons/build_game_icons.sh
@@ -60,8 +60,9 @@ build_icon ${CURRENT_DIR}/button_start.svg ${BASE_DIR}/assets/icons/button_start
 build_icon ${CURRENT_DIR}/difficulty_easy.svg ${BASE_DIR}/assets/icons/difficulty_easy.png
 build_icon ${CURRENT_DIR}/difficulty_medium.svg ${BASE_DIR}/assets/icons/difficulty_medium.png
 build_icon ${CURRENT_DIR}/difficulty_hard.svg ${BASE_DIR}/assets/icons/difficulty_hard.png
-build_icon ${CURRENT_DIR}/size_2.svg ${BASE_DIR}/assets/icons/size_2.png
-build_icon ${CURRENT_DIR}/size_3.svg ${BASE_DIR}/assets/icons/size_3.png
+build_icon ${CURRENT_DIR}/size_2x2.svg ${BASE_DIR}/assets/icons/size_2x2.png
+build_icon ${CURRENT_DIR}/size_3x2.svg ${BASE_DIR}/assets/icons/size_3x2.png
+build_icon ${CURRENT_DIR}/size_3x3.svg ${BASE_DIR}/assets/icons/size_3x3.png
 build_icon ${CURRENT_DIR}/skins/empty.svg ${BASE_DIR}/assets/skins/empty.png
 
 # Skins
diff --git a/icons/size_2.svg b/icons/size_2.svg
deleted file mode 100644
index a5a6172..0000000
--- a/icons/size_2.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="2" fill="#6afffe"/><path d="m8.016 8.1944v83.701h83.701v-83.701zm60.683 60.683h-14.648v-14.648h14.648zm0 4.185v14.648h-14.648v-14.648zm4.185 0h14.648v14.648h-14.648zm0-4.185v-14.648h14.648v14.648zm0-23.018v-14.648h14.648v14.648zm-4.185 0h-14.648v-14.648h14.648zm-23.018 0h-14.648v-14.648h14.648zm0 8.3701v14.648h-14.648v-14.648zm0 18.833v14.648h-14.648v-14.648zm41.85-46.035h-14.648v-14.648h14.648zm-18.833-14.648v14.648h-14.648v-14.648zm-23.018 14.648h-14.648v-14.648h14.648zm-33.48-14.648h14.648v14.648h-14.648zm0 18.833h14.648v14.648h-14.648zm0 23.018h14.648v14.648h-14.648zm0 18.833h14.648v14.648h-14.648z" stroke-width="2.0925"/></svg>
diff --git a/icons/size_2x2.svg b/icons/size_2x2.svg
new file mode 100644
index 0000000..bb4ec58
--- /dev/null
+++ b/icons/size_2x2.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 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="0" fill="none" stroke="#000"/><path d="m-0.16372-0.23334v100.4h100.4v-100.4zm72.788 72.788h-17.569v-17.569h17.569zm0 5.0198v17.569h-17.569v-17.569zm5.0198 0h17.569v17.569h-17.569zm0-5.0198v-17.569h17.569v17.569zm0-27.61v-17.569h17.569v17.569zm-5.0198 0h-17.569v-17.569h17.569zm-27.61 0h-17.569v-17.569h17.569zm0 10.04v17.569h-17.569v-17.569zm0 22.59v17.569h-17.569v-17.569zm50.198-55.217h-17.569v-17.569h17.569zm-22.59-17.569v17.569h-17.569v-17.569zm-27.61 17.569h-17.569v-17.569h17.569zm-40.158-17.569h17.569v17.569h-17.569zm0 22.59h17.569v17.569h-17.569zm0 27.61h17.569v17.569h-17.569zm0 22.59h17.569v17.569h-17.569z" stroke-width="2.5098"/><g transform="matrix(1.2347 0 0 1.2347 -11.926 -14.48)" fill="#00c700" stroke="#003e00" stroke-width="1.6198" aria-label="2x2"><path d="m35.254 91.326h-23.867q0.41016-3.5352 2.4805-6.6406 2.0898-3.125 7.8125-7.3633 3.4961-2.5977 4.4727-3.9453 0.97656-1.3477 0.97656-2.5586 0-1.3086-0.97656-2.2266-0.95703-0.9375-2.4219-0.9375-1.5234 0-2.5 0.95703-0.95703 0.95703-1.2891 3.3789l-7.9688-0.64453q0.46875-3.3594 1.7188-5.2344 1.25-1.8945 3.5156-2.8906 2.2852-1.0156 6.3086-1.0156 4.1992 0 6.5234 0.95703 2.3438 0.95703 3.6719 2.9492 1.3477 1.9727 1.3477 4.4336 0 2.6172-1.543 5-1.5234 2.3828-5.5664 5.2344-2.4023 1.6602-3.2227 2.3242-0.80078 0.66406-1.8945 1.7383h12.422z"/><path d="m37.617 70.584h9.4336l3.3008 5.7812 3.8281-5.7812h8.7695l-7.0703 9.8828 7.5781 10.859h-9.2773l-3.8281-6.6797-4.5117 6.6797h-8.6133l7.5391-10.859z"/><path d="m88.613 91.326h-23.867q0.41016-3.5352 2.4805-6.6406 2.0898-3.125 7.8125-7.3633 3.4961-2.5977 4.4727-3.9453 0.97656-1.3477 0.97656-2.5586 0-1.3086-0.97656-2.2266-0.95703-0.9375-2.4219-0.9375-1.5234 0-2.5 0.95703-0.95703 0.95703-1.2891 3.3789l-7.9688-0.64453q0.46875-3.3594 1.7188-5.2344 1.25-1.8945 3.5156-2.8906 2.2852-1.0156 6.3086-1.0156 4.1992 0 6.5234 0.95703 2.3438 0.95703 3.6719 2.9492 1.3477 1.9727 1.3477 4.4336 0 2.6172-1.543 5-1.5234 2.3828-5.5664 5.2344-2.4023 1.6602-3.2227 2.3242-0.80078 0.66406-1.8945 1.7383h12.422z"/></g></svg>
diff --git a/icons/size_3.svg b/icons/size_3.svg
deleted file mode 100644
index 1b7e516..0000000
--- a/icons/size_3.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="2" fill="#6afffe"/><path d="m65.824 4.0024h-62v90h90v-90zm9 79v-8h8v8zm8 2v7h-8v-7zm-38-2v-8h8v8zm8 2v7h-8v-7zm-38-2v-8h8v8zm8 2v7h-8v-7zm0-70v8h-8v-8zm-8-2v-7h8v7zm38 2v8h-8v-8zm-8-2v-7h8v7zm0 30v-7h8v7zm8 2v8h-8v-8zm-10-2h-7v-7h7zm0 2v8h-7v-8zm0 10v7h-7v-7zm2 0h8v7h-8zm10 0h7v7h-7zm0-2v-8h7v8zm0-10v-7h7v7zm0-11v-7h7v7zm-2 0h-8v-7h8zm-10 0h-7v-7h7zm-11 0h-7v-7h7zm0 4v7h-7v-7zm0 9v8h-7v-8zm0 10v7h-7v-7zm0 11v7h-7v-7zm4 0h7v7h-7zm9 0h8v7h-8zm10 0h7v7h-7zm11 0h7v7h-7zm0-4v-7h7v7zm0-9v-8h7v8zm0-10v-7h7v7zm0-11v-7h7v7zm0-9v-8h7v8zm-4 0h-7v-8h7zm-19 0h-7v-8h7zm-11 0h-7v-8h7zm-9 2v7h-8v-7zm0 11v7h-8v-7zm0 9v8h-8v-8zm0 10v7h-8v-7zm0 11v7h-8v-7zm2 9h7v8h-7zm11 0h7v8h-7zm19 0h7v8h-7zm11 0h7v8h-7zm9-2v-7h8v7zm0-11v-7h8v7zm0-9v-8h8v8zm0-10v-7h8v7zm0-11v-7h8v7zm0-9v-8h8v8zm0-10v-7h8v7zm-2-7v7h-7v-7zm-11 7h-7v-7h7zm-19-7v7h-7v-7zm-11 7h-7v-7h7zm-26-7h7v7h-7zm0 9h7v8h-7zm0 10h7v7h-7zm0 11h7v7h-7zm0 9h7v8h-7zm0 10h7v7h-7zm0 11h7v7h-7zm0 9h7v8h-7zm0 10h7v7h-7zm19 7v-7h7v7zm11-7h7v7h-7zm19 7v-7h7v7zm11-7h7v7h-7zm26 7h-7v-7h7zm0-9h-7v-8h7zm0-10h-7v-7h7zm0-11h-7v-7h7zm0-9h-7v-8h7zm0-10h-7v-7h7zm0-11h-7v-7h7zm0-9h-7v-8h7zm-7-10v-7h7v7z"/></svg>
diff --git a/icons/size_3x2.svg b/icons/size_3x2.svg
new file mode 100644
index 0000000..355de34
--- /dev/null
+++ b/icons/size_3x2.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 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="0" fill="none" stroke="#000"/><path d="m0.14969-0.42875v100.8h99.863v-100.8zm69.716 82.666v-10.835h11.314v10.835zm11.314 4.0477v10.835h-11.314v-10.835zm-62.197-4.0477v-10.835h11.314v10.835zm11.314 4.0477v10.835h-11.314v-10.835zm39.569-72.627v-10.835h11.314v10.835zm11.314 4.0477v10.835h-11.314v-10.835zm-15.342-4.0477h-11.314v-10.835h11.314zm0 4.0477v10.835h-11.314v-10.835zm0 19.407v10.835h-11.314v-10.835zm4.0278 0h11.314v10.835h-11.314zm15.342 0h11.314v10.835h-11.314zm0-8.5725v-10.835h11.314v10.835zm0-14.882v-10.835h11.314v10.835zm-39.569-10.835v10.835h-11.314v-10.835zm0 14.882v10.835h-11.314v-10.835zm0 19.407v10.835h-11.314v-10.835zm0 14.882v10.835h-11.314v-10.835zm8.8853 0h11.314v10.835h-11.314zm15.342 0h11.314v10.835h-11.314zm15.343 0h11.314v10.835h-11.314zm-54.91-49.172v10.835h-11.314v-10.835zm0 14.882v10.835h-11.314v-10.835zm0 19.407v10.835h-11.314v-10.835zm0 14.882v10.835h-11.314v-10.835zm4.0278 19.407h11.314v10.835h-11.314zm20.2 0h11.314v10.835h-11.314zm30.684 0h11.314v10.835h-11.314zm-81.567-68.58h11.314v10.835h-11.314zm0 14.882h11.314v10.835h-11.314zm0 19.407h11.314v10.835h-11.314zm0 14.882h11.314v10.835h-11.314zm0 19.407h11.314v10.835h-11.314zm0 14.882h11.314v10.835h-11.314zm30.684 10.835v-10.835h11.314v10.835zm20.2-10.835h11.314v10.835h-11.314zm30.684 10.835v-10.835h11.314v10.835z" stroke-width="1.6844"/><g transform="matrix(1.2405 0 0 1.2405 -12.136 -19.028)" fill="#ff8d05" stroke="#4c2a00" stroke-width="1.6123" aria-label="3x2"><path d="m19.512 73.271-7.5195-1.3477q0.9375-3.5938 3.5938-5.5078 2.6758-1.9141 7.5586-1.9141 5.6055 0 8.1055 2.0898t2.5 5.2539q0 1.8555-1.0156 3.3594t-3.0664 2.6367q1.6602 0.41016 2.5391 0.95703 1.4258 0.87891 2.207 2.3242 0.80078 1.4258 0.80078 3.418 0 2.5-1.3086 4.8047-1.3086 2.2852-3.7695 3.5352-2.4609 1.2305-6.4648 1.2305-3.9062 0-6.1719-0.91797-2.2461-0.91797-3.7109-2.6758-1.4453-1.7773-2.2266-4.4531l7.9492-1.0547q0.46875 2.4023 1.4453 3.3398 0.99609 0.91797 2.5195 0.91797 1.6016 0 2.6562-1.1719 1.0742-1.1719 1.0742-3.125 0-1.9922-1.0352-3.0859-1.0156-1.0938-2.7734-1.0938-0.9375 0-2.5781 0.46875l0.41016-5.6836q0.66406 0.09766 1.0352 0.09766 1.5625 0 2.5977-0.99609 1.0547-0.99609 1.0547-2.3633 0-1.3086-0.78125-2.0898t-2.1484-0.78125q-1.4062 0-2.2852 0.85938-0.87891 0.83984-1.1914 2.9688z"/><path d="m37.441 72.88h9.4336l3.3008 5.7812 3.8281-5.7812h8.7695l-7.0703 9.8828 7.5781 10.859h-9.2773l-3.8281-6.6797-4.5117 6.6797h-8.6133l7.5391-10.859z"/><path d="m88.438 93.622h-23.867q0.41016-3.5352 2.4805-6.6406 2.0898-3.125 7.8125-7.3633 3.4961-2.5977 4.4727-3.9453 0.97656-1.3477 0.97656-2.5586 0-1.3086-0.97656-2.2266-0.95703-0.9375-2.4219-0.9375-1.5234 0-2.5 0.95703-0.95703 0.95703-1.2891 3.3789l-7.9688-0.64453q0.46875-3.3594 1.7188-5.2344 1.25-1.8945 3.5156-2.8906 2.2852-1.0156 6.3086-1.0156 4.1992 0 6.5234 0.95703 2.3438 0.95703 3.6719 2.9492 1.3477 1.9727 1.3477 4.4336 0 2.6172-1.543 5-1.5234 2.3828-5.5664 5.2344-2.4023 1.6602-3.2227 2.3242-0.80078 0.66406-1.8945 1.7383h12.422z"/></g></svg>
diff --git a/icons/size_3x3.svg b/icons/size_3x3.svg
new file mode 100644
index 0000000..3037d35
--- /dev/null
+++ b/icons/size_3x3.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 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="0" fill="none" stroke="#000"/><path d="m68.799-0.020495h-69.133v100.35h100.35v-100.35zm10.035 88.089v-8.9204h8.9204v8.9204zm8.9204 2.2301v7.8053h-8.9204v-7.8053zm-42.372-2.2301v-8.9204h8.9204v8.9204zm8.9204 2.2301v7.8053h-8.9204v-7.8053zm-42.372-2.2301v-8.9204h8.9204v8.9204zm8.9204 2.2301v7.8053h-8.9204v-7.8053zm0-78.053v8.9204h-8.9204v-8.9204zm-8.9204-2.2301v-7.8053h8.9204v7.8053zm42.372 2.2301v8.9204h-8.9204v-8.9204zm-8.9204-2.2301v-7.8053h8.9204v7.8053zm0 33.452v-7.8053h8.9204v7.8053zm8.9204 2.2301v8.9204h-8.9204v-8.9204zm-11.151-2.2301h-7.8053v-7.8053h7.8053zm0 2.2301v8.9204h-7.8053v-8.9204zm0 11.151v7.8053h-7.8053v-7.8053zm2.2301 0h8.9204v7.8053h-8.9204zm11.151 0h7.8053v7.8053h-7.8053zm0-2.2301v-8.9204h7.8053v8.9204zm0-11.151v-7.8053h7.8053v7.8053zm0-12.266v-7.8053h7.8053v7.8053zm-2.2301 0h-8.9204v-7.8053h8.9204zm-11.151 0h-7.8053v-7.8053h7.8053zm-12.266 0h-7.8053v-7.8053h7.8053zm0 4.4603v7.8053h-7.8053v-7.8053zm0 10.035v8.9204h-7.8053v-8.9204zm0 11.151v7.8053h-7.8053v-7.8053zm0 12.266v7.8053h-7.8053v-7.8053zm4.4603 0h7.8053v7.8053h-7.8053zm10.035 0h8.9204v7.8053h-8.9204zm11.151 0h7.8053v7.8053h-7.8053zm12.266 0h7.8053v7.8053h-7.8053zm0-4.4603v-7.8053h7.8053v7.8053zm0-10.035v-8.9204h7.8053v8.9204zm0-11.151v-7.8053h7.8053v7.8053zm0-12.266v-7.8053h7.8053v7.8053zm0-10.035v-8.9204h7.8053v8.9204zm-4.4603 0h-7.8053v-8.9204h7.8053zm-21.186 0h-7.8053v-8.9204h7.8053zm-12.266 0h-7.8053v-8.9204h7.8053zm-10.035 2.2301v7.8053h-8.9204v-7.8053zm0 12.266v7.8053h-8.9204v-7.8053zm0 10.035v8.9204h-8.9204v-8.9204zm0 11.151v7.8053h-8.9204v-7.8053zm0 12.266v7.8053h-8.9204v-7.8053zm2.2301 10.035h7.8053v8.9204h-7.8053zm12.266 0h7.8053v8.9204h-7.8053zm21.186 0h7.8053v8.9204h-7.8053zm12.266 0h7.8053v8.9204h-7.8053zm10.035-2.2301v-7.8053h8.9204v7.8053zm0-12.266v-7.8053h8.9204v7.8053zm0-10.035v-8.9204h8.9204v8.9204zm0-11.151v-7.8053h8.9204v7.8053zm0-12.266v-7.8053h8.9204v7.8053zm0-10.035v-8.9204h8.9204v8.9204zm0-11.151v-7.8053h8.9204v7.8053zm-2.2301-7.8053v7.8053h-7.8053v-7.8053zm-12.266 7.8053h-7.8053v-7.8053h7.8053zm-21.186-7.8053v7.8053h-7.8053v-7.8053zm-12.266 7.8053h-7.8053v-7.8053h7.8053zm-28.991-7.8053h7.8053v7.8053h-7.8053zm0 10.035h7.8053v8.9204h-7.8053zm0 11.151h7.8053v7.8053h-7.8053zm0 12.266h7.8053v7.8053h-7.8053zm0 10.035h7.8053v8.9204h-7.8053zm0 11.151h7.8053v7.8053h-7.8053zm0 12.266h7.8053v7.8053h-7.8053zm0 10.035h7.8053v8.9204h-7.8053zm0 11.151h7.8053v7.8053h-7.8053zm21.186 7.8053v-7.8053h7.8053v7.8053zm12.266-7.8053h7.8053v7.8053h-7.8053zm21.186 7.8053v-7.8053h7.8053v7.8053zm12.266-7.8053h7.8053v7.8053h-7.8053zm28.991 7.8053h-7.8053v-7.8053h7.8053zm0-10.035h-7.8053v-8.9204h7.8053zm0-11.151h-7.8053v-7.8053h7.8053zm0-12.266h-7.8053v-7.8053h7.8053zm0-10.035h-7.8053v-8.9204h7.8053zm0-11.151h-7.8053v-7.8053h7.8053zm0-12.266h-7.8053v-7.8053h7.8053zm0-10.035h-7.8053v-8.9204h7.8053zm-7.8053-11.151v-7.8053h7.8053v7.8053z" stroke-width="1.1151"/><g transform="matrix(1.2388 0 0 1.2388 -11.249 -16.591)" fill="#f00" stroke="#500000" stroke-width="1.6145" aria-label="3x3"><path d="m19.443 72.913-7.5195-1.3477q0.9375-3.5938 3.5938-5.5078 2.6758-1.9141 7.5586-1.9141 5.6055 0 8.1055 2.0898t2.5 5.2539q0 1.8555-1.0156 3.3594t-3.0664 2.6367q1.6602 0.41016 2.5391 0.95703 1.4258 0.87891 2.207 2.3242 0.80078 1.4258 0.80078 3.418 0 2.5-1.3086 4.8047-1.3086 2.2852-3.7695 3.5352-2.4609 1.2305-6.4648 1.2305-3.9062 0-6.1719-0.91797-2.2461-0.91797-3.7109-2.6758-1.4453-1.7773-2.2266-4.4531l7.9492-1.0547q0.46875 2.4023 1.4453 3.3398 0.99609 0.91797 2.5195 0.91797 1.6016 0 2.6562-1.1719 1.0742-1.1719 1.0742-3.125 0-1.9922-1.0352-3.0859-1.0156-1.0938-2.7734-1.0938-0.9375 0-2.5781 0.46875l0.41016-5.6836q0.66406 0.09766 1.0352 0.09766 1.5625 0 2.5977-0.99609 1.0547-0.99609 1.0547-2.3633 0-1.3086-0.78125-2.0898t-2.1484-0.78125q-1.4062 0-2.2852 0.85938-0.87891 0.83984-1.1914 2.9688z"/><path d="m37.373 72.522h9.4336l3.3008 5.7812 3.8281-5.7812h8.7695l-7.0703 9.8828 7.5781 10.859h-9.2773l-3.8281-6.6797-4.5117 6.6797h-8.6133l7.5391-10.859z"/><path d="m72.803 72.913-7.5195-1.3477q0.9375-3.5938 3.5938-5.5078 2.6758-1.9141 7.5586-1.9141 5.6055 0 8.1055 2.0898t2.5 5.2539q0 1.8555-1.0156 3.3594t-3.0664 2.6367q1.6602 0.41016 2.5391 0.95703 1.4258 0.87891 2.207 2.3242 0.80078 1.4258 0.80078 3.418 0 2.5-1.3086 4.8047-1.3086 2.2852-3.7695 3.5352-2.4609 1.2305-6.4648 1.2305-3.9062 0-6.1719-0.91797-2.2461-0.91797-3.7109-2.6758-1.4453-1.7773-2.2266-4.4531l7.9492-1.0547q0.46875 2.4023 1.4453 3.3398 0.99609 0.91797 2.5195 0.91797 1.6016 0 2.6562-1.1719 1.0742-1.1719 1.0742-3.125 0-1.9922-1.0352-3.0859-1.0156-1.0938-2.7734-1.0938-0.9375 0-2.5781 0.46875l0.41016-5.6836q0.66406 0.09766 1.0352 0.09766 1.5625 0 2.5977-0.99609 1.0547-0.99609 1.0547-2.3633 0-1.3086-0.78125-2.0898t-2.1484-0.78125q-1.4062 0-2.2852 0.85938-0.87891 0.83984-1.1914 2.9688z"/></g></svg>
diff --git a/lib/entities/cell.dart b/lib/entities/cell.dart
index e4d2cf5..4632c96 100644
--- a/lib/entities/cell.dart
+++ b/lib/entities/cell.dart
@@ -23,8 +23,6 @@ class Cell {
       imageAsset = 'assets/skins/' + myProvider.skin + '_' + this.value.toString() + '.png';
     }
 
-    int size = myProvider.size;
-
     return Container(
       decoration: BoxDecoration(
         color: this.getBackgroundColor(myProvider),
@@ -101,7 +99,8 @@ class Cell {
   }
 
   static Border getCellBorders(Data myProvider, int row, int col) {
-    int size = myProvider.size;
+    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
+    int blockSizeVertical = myProvider.blockSizeVertical;
 
     Border borders = Border.all(
       color: cellBorderSelectedColor,
@@ -110,10 +109,10 @@ class Cell {
 
     if (col != myProvider.currentCellCol || row != myProvider.currentCellRow) {
       borders = Border(
-        top: BorderSide(width: cellBorderWidth, color: ((row % size) == 0) ? cellBorderDarkColor : cellBorderLightColor),
-        left: BorderSide(width: cellBorderWidth, color: ((col % size) == 0) ? cellBorderDarkColor : cellBorderLightColor),
-        right: BorderSide(width: cellBorderWidth, color: (((col + 1) % size) == 0) ? cellBorderDarkColor : cellBorderLightColor),
-        bottom: BorderSide(width: cellBorderWidth, color: (((row + 1) % size) == 0) ? cellBorderDarkColor : cellBorderLightColor),
+        top: BorderSide(width: cellBorderWidth, color: ((row % blockSizeVertical) == 0) ? cellBorderDarkColor : cellBorderLightColor),
+        left: BorderSide(width: cellBorderWidth, color: ((col % blockSizeHorizontal) == 0) ? cellBorderDarkColor : cellBorderLightColor),
+        right: BorderSide(width: cellBorderWidth, color: (((col + 1) % blockSizeHorizontal) == 0) ? cellBorderDarkColor : cellBorderLightColor),
+        bottom: BorderSide(width: cellBorderWidth, color: (((row + 1) % blockSizeVertical) == 0) ? cellBorderDarkColor : cellBorderLightColor),
       );
     }
 
diff --git a/lib/layout/board.dart b/lib/layout/board.dart
index cd4905e..fcc8806 100644
--- a/lib/layout/board.dart
+++ b/lib/layout/board.dart
@@ -28,15 +28,15 @@ class Board {
   }
 
   static Table buildGameTileset(Data myProvider) {
-    int size = myProvider.size;
+    int boardSize = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
     List cells = myProvider.cells;
 
     return Table(
       defaultColumnWidth: IntrinsicColumnWidth(),
       children: [
-        for (var row = 0; row < pow(size, 2); row++)
+        for (var row = 0; row < boardSize; row++)
           TableRow(children: [
-            for (var col = 0; col < pow(size, 2); col++)
+            for (var col = 0; col < boardSize; col++)
               Column(children: [
                 cells[row][col].widget(
                   myProvider,
diff --git a/lib/layout/game.dart b/lib/layout/game.dart
index bda08eb..6b09b41 100644
--- a/lib/layout/game.dart
+++ b/lib/layout/game.dart
@@ -26,12 +26,11 @@ class Game {
 
   static Container buildSelectCellValueBar(Data myProvider) {
     List cells = myProvider.cells;
-    int size = myProvider.size;
 
     Color borderColor = Colors.blue;
 
     bool isCellSelected = (myProvider.currentCellCol != null && myProvider.currentCellRow != null);
-    int maxValue = pow(size, 2) + 1;
+    int maxValue = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
 
     return Container(
       margin: EdgeInsets.all(2),
@@ -42,7 +41,7 @@ class Game {
         children: [
           TableRow(
             children: [
-              for (var value = 0; value < maxValue; value++)
+              for (var value = 0; value <= maxValue; value++)
                 Column(
                   children: [
                     Cell(
diff --git a/lib/layout/parameters.dart b/lib/layout/parameters.dart
index b4bb302..9ac761c 100644
--- a/lib/layout/parameters.dart
+++ b/lib/layout/parameters.dart
@@ -70,11 +70,11 @@ class Parameters {
   }
 
 
-  static FlatButton _buildParameterButton(Data myProvider, String parameterCode, var parameterValue) {
+  static FlatButton _buildParameterButton(Data myProvider, String parameterCode, String parameterValue) {
     String currentValue = myProvider.getParameterValue(parameterCode).toString();
 
-    bool isActive = (parameterValue.toString() == currentValue);
-    String imageAsset = 'assets/icons/' + parameterCode + '_' + parameterValue.toString() + '.png';
+    bool isActive = (parameterValue == currentValue);
+    String imageAsset = 'assets/icons/' + parameterCode + '_' + parameterValue + '.png';
 
     return FlatButton(
       child: Container(
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
index ea939bf..0225b29 100644
--- a/lib/provider/data.dart
+++ b/lib/provider/data.dart
@@ -4,7 +4,7 @@ class Data extends ChangeNotifier {
 
   // Configuration available values
   List _availableDifficultyLevels = ['easy', 'medium', 'hard'];
-  List _availableSizes = [2, 3];
+  List _availableSizes = ['2x2', '3x2', '3x3'];
   List _availableSkins = ['default', 'food', 'nature'];
 
   List get availableDifficultyLevels => _availableDifficultyLevels;
@@ -13,12 +13,14 @@ class Data extends ChangeNotifier {
 
   // Application default configuration
   String _level = 'medium';
-  int _size = 3;
+  String _size = '3x3';
   String _skin = 'default';
   bool _showConflicts = false;
 
   // Game data
   bool _stateRunning = false;
+  int _blockSizeVertical = null;
+  int _blockSizeHorizontal = null;
   List _cells = [];
   int _currentCellCol = null;
   int _currentCellRow = null;
@@ -29,9 +31,13 @@ class Data extends ChangeNotifier {
     notifyListeners();
   }
 
-  int get size => _size;
-  set updateSize(int size) {
+  String get size => _size;
+  int get blockSizeVertical => _blockSizeVertical;
+  int get blockSizeHorizontal => _blockSizeHorizontal;
+  set updateSize(String size) {
     _size = size;
+    _blockSizeHorizontal = int.parse(_size.split('x')[0]);
+    _blockSizeVertical = int.parse(_size.split('x')[1]);
     notifyListeners();
   }
 
@@ -69,7 +75,7 @@ class Data extends ChangeNotifier {
     }
   }
 
-  setParameterValue(String parameterCode, var parameterValue) {
+  setParameterValue(String parameterCode, String parameterValue) {
     switch(parameterCode) {
       case 'difficulty': { updateLevel = parameterValue; }
       break;
diff --git a/lib/utils/board_utils.dart b/lib/utils/board_utils.dart
index 539bf4d..2c93084 100644
--- a/lib/utils/board_utils.dart
+++ b/lib/utils/board_utils.dart
@@ -22,30 +22,33 @@ class BoardUtils {
 
 
   static Future<void> pickGrid(Data myProvider) async {
-    int size = myProvider.size;
-
     String grid;
     RandomPickGrid randomPickGrid;
 
     randomPickGrid = RandomPickGrid();
-    await randomPickGrid.init(myProvider.level, size);
+    await randomPickGrid.init(myProvider.level, myProvider.size);
 
     if (randomPickGrid.grid != null) {
       grid = randomPickGrid.grid;
     }
 
-    if (grid.length == pow(size, 4)) {
-      myProvider.updateCells = BoardUtils.createBoardFromTemplate(grid);
+    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
+    int blockSizeVertical = myProvider.blockSizeVertical;
+
+    if (grid.length == pow(blockSizeHorizontal * blockSizeVertical, 2)) {
+      print('Picked grid from template: ' + grid);
+      bool isSymetric = (blockSizeHorizontal == blockSizeVertical);
+      myProvider.updateCells = BoardUtils.createBoardFromTemplate(grid, isSymetric);
     }
   }
 
 
-  static List createEmptyBoard(int size) {
+  static List createEmptyBoard(int boardSize) {
     int index = 0;
     List cells = [];
-    for (var rowIndex = 0; rowIndex < pow(size, 2); rowIndex++) {
+    for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
       List row = [];
-      for (var colIndex = 0; colIndex < pow(size, 2); colIndex++) {
+      for (var colIndex = 0; colIndex < boardSize; colIndex++) {
         row.add(Cell(0, false));
       }
       cells.add(row);
@@ -55,44 +58,51 @@ class BoardUtils {
   }
 
 
-  static List createBoardFromTemplate(String grid) {
+  static List createBoardFromTemplate(String grid, bool isSymetric) {
     List cells = [];
-    int size = int.parse(pow(grid.length, 1/4).toStringAsFixed(0));
-    int sideLength = pow(size, 2);
+    int boardSize = int.parse(pow(grid.length, 1/2).toStringAsFixed(0));
 
     int index = 0;
-    for (var rowIndex = 0; rowIndex < sideLength; rowIndex++) {
+    for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
       List row = [];
-      for (var colIndex = 0; colIndex < sideLength; colIndex++) {
+      for (var colIndex = 0; colIndex < boardSize; colIndex++) {
         int value = int.parse(grid[index++]);
         row.add(Cell(value, (value != 0)));
       }
       cells.add(row);
     }
 
-    List<String> allowedFlip = ['', 'horizontal', 'vertical'];
-    List<String> allowedRotate = ['', 'left', 'right'];
+    List<String> allowedFlip = ['none', 'horizontal', 'vertical'];
+    List<String> allowedRotate = ['none', 'left', 'right'];
+
+    // Forbid rotation if blocks are not symetric
+    if (!isSymetric) {
+      allowedRotate = ['none'];
+    }
 
     var rand = new Random();
     String flip = allowedFlip[rand.nextInt(allowedFlip.length)];
     String rotate = allowedRotate[rand.nextInt(allowedRotate.length)];
 
+    print('flip board: ' + flip);
+    print('rotate board: ' + rotate);
+
     switch(flip) {
       case 'horizontal': {
-        List transformedBoard = createEmptyBoard(size);
-        for (var rowIndex = 0; rowIndex < sideLength; rowIndex++) {
-          for (var colIndex = 0; colIndex < sideLength; colIndex++) {
-            transformedBoard[rowIndex][colIndex].value = cells[sideLength - rowIndex - 1][colIndex].value;
+        List transformedBoard = createEmptyBoard(boardSize);
+        for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+          for (var colIndex = 0; colIndex < boardSize; colIndex++) {
+            transformedBoard[rowIndex][colIndex].value = cells[boardSize - rowIndex - 1][colIndex].value;
           }
         }
         cells = transformedBoard;
       }
       break;
       case 'vertical': {
-        List transformedBoard = createEmptyBoard(size);
-        for (var rowIndex = 0; rowIndex < sideLength; rowIndex++) {
-          for (var colIndex = 0; colIndex < sideLength; colIndex++) {
-            transformedBoard[rowIndex][colIndex].value = cells[rowIndex][sideLength - colIndex - 1].value;
+        List transformedBoard = createEmptyBoard(boardSize);
+        for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+          for (var colIndex = 0; colIndex < boardSize; colIndex++) {
+            transformedBoard[rowIndex][colIndex].value = cells[rowIndex][boardSize - colIndex - 1].value;
           }
         }
         cells = transformedBoard;
@@ -102,20 +112,20 @@ class BoardUtils {
 
     switch(rotate) {
       case 'left': {
-        List transformedBoard = createEmptyBoard(size);
-        for (var rowIndex = 0; rowIndex < sideLength; rowIndex++) {
-          for (var colIndex = 0; colIndex < sideLength; colIndex++) {
-            transformedBoard[rowIndex][colIndex].value = cells[colIndex][sideLength - rowIndex - 1].value;
+        List transformedBoard = createEmptyBoard(boardSize);
+        for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+          for (var colIndex = 0; colIndex < boardSize; colIndex++) {
+            transformedBoard[rowIndex][colIndex].value = cells[colIndex][boardSize - rowIndex - 1].value;
           }
         }
         cells = transformedBoard;
       }
       break;
       case 'right': {
-        List transformedBoard = createEmptyBoard(size);
-        for (var rowIndex = 0; rowIndex < sideLength; rowIndex++) {
-          for (var colIndex = 0; colIndex < sideLength; colIndex++) {
-            transformedBoard[rowIndex][colIndex].value = cells[sideLength - colIndex - 1][rowIndex].value;
+        List transformedBoard = createEmptyBoard(boardSize);
+        for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+          for (var colIndex = 0; colIndex < boardSize; colIndex++) {
+            transformedBoard[rowIndex][colIndex].value = cells[boardSize - colIndex - 1][rowIndex].value;
           }
         }
         cells = transformedBoard;
@@ -124,8 +134,8 @@ class BoardUtils {
     }
 
     // Fix cells fixed states
-    for (var rowIndex = 0; rowIndex < sideLength; rowIndex++) {
-      for (var colIndex = 0; colIndex < sideLength; colIndex++) {
+    for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+      for (var colIndex = 0; colIndex < boardSize; colIndex++) {
         cells[rowIndex][colIndex].isFixed = (cells[rowIndex][colIndex].value != 0) ? true : false;
       }
     }
@@ -138,21 +148,24 @@ class BoardUtils {
 
   static bool checkBoardIsSolved(Data myProvider) {
     List cells = myProvider.cells;
-    int size = myProvider.size;
-    int sideLength = pow(size, 2);
+
+    int blockSizeHorizontal = myProvider.blockSizeHorizontal;
+    int blockSizeVertical = myProvider.blockSizeVertical;
+
+    int boardSize = blockSizeHorizontal * blockSizeVertical;
 
     bool isSolved = true;
 
     // reset conflict states
-    for (var row = 0; row < sideLength; row++) {
-      for (var col = 0; col < sideLength; col++) {
+    for (var row = 0; row < boardSize; row++) {
+      for (var col = 0; col < boardSize; col++) {
         cells[row][col].conflictsCount = 0;
       }
     }
 
     // check grid is fully completed
-    for (var row = 0; row < sideLength; row++) {
-      for (var col = 0; col < sideLength; col++) {
+    for (var row = 0; row < boardSize; row++) {
+      for (var col = 0; col < boardSize; col++) {
         if (cells[row][col].value == 0) {
           isSolved = false;
         }
@@ -160,9 +173,9 @@ class BoardUtils {
     }
 
     // check lines does not contains a value twice
-    for (var row = 0; row < sideLength; row++) {
+    for (var row = 0; row < boardSize; row++) {
       List values = [];
-      for (var col = 0; col < sideLength; col++) {
+      for (var col = 0; col < boardSize; col++) {
         int value = cells[row][col].value;
         if (value != 0) {
           values.add(value);
@@ -172,7 +185,7 @@ class BoardUtils {
       if (values.length != distinctValues.length) {
         print('line ' + row.toString() + ' contains duplicates');
         // Add line to cells in conflict
-        for (var col = 0; col < sideLength; col++) {
+        for (var col = 0; col < boardSize; col++) {
           cells[row][col].conflictsCount++;
         }
         isSolved = false;
@@ -180,9 +193,9 @@ class BoardUtils {
     }
 
     // check columns does not contains a value twice
-    for (var col = 0; col < sideLength; col++) {
+    for (var col = 0; col < boardSize; col++) {
       List values = [];
-      for (var row = 0; row < sideLength; row++) {
+      for (var row = 0; row < boardSize; row++) {
         int value = cells[row][col].value;
         if (value != 0) {
           values.add(value);
@@ -192,7 +205,7 @@ class BoardUtils {
       if (values.length != distinctValues.length) {
         print('column ' + col.toString() + ' contains duplicates');
         // Add column to cells in conflict
-        for (var row = 0; row < sideLength; row++) {
+        for (var row = 0; row < boardSize; row++) {
           cells[row][col].conflictsCount++;
         }
         isSolved = false;
@@ -200,14 +213,16 @@ class BoardUtils {
     }
 
     // check blocks does not contains a value twice
-    for (var blockRow = 0; blockRow < size; blockRow++) {
-      for (var blockCol = 0; blockCol < size; blockCol++) {
+    int horizontalBlocksCount = blockSizeVertical;
+    int verticalBlocksCount = blockSizeHorizontal;
+    for (var blockRow = 0; blockRow < verticalBlocksCount; blockRow++) {
+      for (var blockCol = 0; blockCol < horizontalBlocksCount; blockCol++) {
         List values = [];
 
-        for (var rowInBlock = 0; rowInBlock < size; rowInBlock++) {
-          for (var colInBlock = 0; colInBlock < size; colInBlock++) {
-            int row = (blockRow * size) + rowInBlock;
-            int col = (blockCol * size) + colInBlock;
+        for (var rowInBlock = 0; rowInBlock < blockSizeVertical; rowInBlock++) {
+          for (var colInBlock = 0; colInBlock < blockSizeHorizontal; colInBlock++) {
+            int row = (blockRow * blockSizeVertical) + rowInBlock;
+            int col = (blockCol * blockSizeHorizontal) + colInBlock;
             int value = cells[row][col].value;
             if (value != 0) {
               values.add(value);
@@ -219,10 +234,10 @@ class BoardUtils {
         if (values.length != distinctValues.length) {
           print('block [' + blockCol.toString() + ',' + blockRow.toString() + '] contains duplicates');
           // Add blocks to cells in conflict
-          for (var rowInBlock = 0; rowInBlock < size; rowInBlock++) {
-            for (var colInBlock = 0; colInBlock < size; colInBlock++) {
-              int row = (blockRow * size) + rowInBlock;
-              int col = (blockCol * size) + colInBlock;
+          for (var rowInBlock = 0; rowInBlock < blockSizeVertical; rowInBlock++) {
+            for (var colInBlock = 0; colInBlock < blockSizeHorizontal; colInBlock++) {
+              int row = (blockRow * blockSizeVertical) + rowInBlock;
+              int col = (blockCol * blockSizeHorizontal) + colInBlock;
               cells[row][col].conflictsCount++;
             }
           }
diff --git a/lib/utils/game_utils.dart b/lib/utils/game_utils.dart
index dd9d43a..4f47e67 100644
--- a/lib/utils/game_utils.dart
+++ b/lib/utils/game_utils.dart
@@ -8,8 +8,9 @@ class GameUtils {
   }
 
   static Future<void> startGame(Data myProvider) async {
+    print('Start new game: ' + myProvider.size);
     myProvider.updateStateRunning = true;
-    myProvider.updateCells = BoardUtils.createEmptyBoard(myProvider.size);
+    myProvider.updateCells = BoardUtils.createEmptyBoard(myProvider.blockSizeHorizontal * myProvider.blockSizeVertical);
     BoardUtils.pickGrid(myProvider);
   }
 }
diff --git a/lib/utils/random_pick_grid.dart b/lib/utils/random_pick_grid.dart
index 5348f27..58a0c45 100644
--- a/lib/utils/random_pick_grid.dart
+++ b/lib/utils/random_pick_grid.dart
@@ -6,27 +6,25 @@ class RandomPickGrid {
 
   String _grid;
 
-  init(String difficulty, int size) async {
+  init(String difficulty, String size) async {
     _grid = '';
     await gridFromLocalFile(difficulty, size);
   }
 
-  Future<void> gridFromLocalFile(String difficulty, int size) async {
-    String sizeAsString = size.toString() + 'x' + size.toString();
-
+  Future<void> gridFromLocalFile(String difficulty, String size) async {
     // Get global grids list
     List grids;
     try {
       String jsonString = await rootBundle.loadString('assets/files/templates.json');
       final jsonResponse = await json.decode(jsonString);
-      grids = jsonResponse['templates'][sizeAsString][difficulty];
+      grids = jsonResponse['templates'][size][difficulty];
     } catch (e) {
       print("$e");
     }
 
     // Check we have enough grids
     if (grids.length < 1) {
-      print('Not enough grids [' + sizeAsString + ', ' + difficulty + '] in templates.');
+      print('Not enough grids [' + size + ', ' + difficulty + '] in templates.');
     }
 
     // Randomize grids list
-- 
GitLab