From fe5c3b75816c293b6b38736488bc66b334853abd Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 22 Jan 2024 03:10:28 +0000 Subject: [PATCH 01/36] initial setup --- app.rb | 8 +++--- views/basic_calculator.erb | 29 +++++++++++++++++++++ views/calc_font/Calculator.woff | Bin 0 -> 10252 bytes views/layout.erb | 44 ++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 views/basic_calculator.erb create mode 100644 views/calc_font/Calculator.woff diff --git a/app.rb b/app.rb index abbd1c7..de3543a 100644 --- a/app.rb +++ b/app.rb @@ -2,8 +2,8 @@ require "sinatra/reloader" get("/") do - " -

Welcome to your Sinatra App!

-

Define some routes in app.rb

- " + + erb(:basic_calculator) + + end diff --git a/views/basic_calculator.erb b/views/basic_calculator.erb new file mode 100644 index 0000000..859f19a --- /dev/null +++ b/views/basic_calculator.erb @@ -0,0 +1,29 @@ +
+
0
+
+
AC
+
+/-
+
%
+
/
+ +
7
+
8
+
9
+
*
+ +
4
+
5
+
6
+
-
+ +
1
+
2
+
3
+
+
+ +
0
+
.
+
=
+
+
+ diff --git a/views/calc_font/Calculator.woff b/views/calc_font/Calculator.woff new file mode 100644 index 0000000000000000000000000000000000000000..0319ebd1facc0a10cba2eb28545948b74162ad34 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/views/layout.erb b/views/layout.erb index d0e831e..e41ce7c 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -6,7 +6,51 @@ + + + + <%= yield %> From f82f64492db32dd79f5d2f5c27e8801eb41a6f75 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 22 Jan 2024 20:54:05 +0000 Subject: [PATCH 02/36] UI Setup --- views/basic_calculator.erb | 4 - views/calc_font/Calculator.woff | Bin 10252 -> 0 bytes views/fonts/Calculator.ttf | Bin 0 -> 21632 bytes views/fonts/SFDigitalReadout-MediumObli.ttf | Bin 0 -> 40284 bytes views/layout.erb | 108 +++++++++++++------- 5 files changed, 69 insertions(+), 43 deletions(-) delete mode 100644 views/calc_font/Calculator.woff create mode 100644 views/fonts/Calculator.ttf create mode 100644 views/fonts/SFDigitalReadout-MediumObli.ttf diff --git a/views/basic_calculator.erb b/views/basic_calculator.erb index 859f19a..be09250 100644 --- a/views/basic_calculator.erb +++ b/views/basic_calculator.erb @@ -1,5 +1,3 @@ -
-
0
AC
+/-
@@ -25,5 +23,3 @@
.
=
-
- diff --git a/views/calc_font/Calculator.woff b/views/calc_font/Calculator.woff deleted file mode 100644 index 0319ebd1facc0a10cba2eb28545948b74162ad34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10252 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 diff --git a/views/fonts/Calculator.ttf b/views/fonts/Calculator.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8d74251bfea23e2bee3db456b780091c4e9b5ac3 GIT binary patch literal 21632 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 U3N{c=;zbc-v4meZg^sZQ0~19R2><{9 literal 0 HcmV?d00001 diff --git a/views/fonts/SFDigitalReadout-MediumObli.ttf b/views/fonts/SFDigitalReadout-MediumObli.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ad0656a23453f0eabed9fdc3ee12f0d42c0a9a2b GIT binary patch literal 40284 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 literal 0 HcmV?d00001 diff --git a/views/layout.erb b/views/layout.erb index e41ce7c..dceaadd 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -7,50 +7,80 @@ + - +
+
+
00000001
+
This is a test
+
The quick brown fox jumped over the(lazy)dogs
+
00000001
+
00000001
+
00000001
+
00000001
+
00000001
+
<%= yield %> + +
+ From 9c67032f3bb0937177cb241635441c4d36b9b1ba Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 22 Jan 2024 21:21:41 +0000 Subject: [PATCH 03/36] More styling to the calculator face. --- views/fonts/open-sauce.sans-black.ttf | Bin 0 -> 71180 bytes views/layout.erb | 60 +------------------------- views/styles/stylesheet.css | 58 +++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 59 deletions(-) create mode 100644 views/fonts/open-sauce.sans-black.ttf create mode 100644 views/styles/stylesheet.css diff --git a/views/fonts/open-sauce.sans-black.ttf b/views/fonts/open-sauce.sans-black.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ea2105d1c52dab216761ae0cb2e7be2e25f70936 GIT binary patch literal 71180 zcmeFa37lL-^)Fs^Z|~bo@3YTz_e{^0%uHs_Ht8fYS!O2tLMA|x30WZtA;}L3LKq;d zB7z{eAVz+O(I09g5EcOe^HV^cA_5{H1VKRsf`}}JbieO8_xA1XnMnfbd!P4z|JO6O zy1Mo{=hUfFr%u%sQV8LLV-gkJi)PQnFDYcmgm2r-?w%R8_v|$Y8iU^}X3n3t==;vG$g{Ye^gmvk>MUBm8#4p<+#JIgkzv{HjgIf!l>mL!K*@g<1 zop$z)3d^~9w+d-_1Mzd$ZC$_l=62r`LRve8@C4TnZr_UVe8eBZw{88Vo$LO1$!EVL zMEfcs?)Ge0JGdr%`!CNI;w?(oz5xN2nCVsgrur&3Y~FEB^V7CX`2Byf80EH&Q>*=uL$w}c}QQeWpMM_OTz=`%lkK>x?Nk(+`ePuFHgNeh*Sys z^T^h1YqzeLa^&km2GKup2OuMa3lDu1;l^V}m{U~1jfw`iO=1?@Ua=nTMzI_2rQ%h% zuZce*_3PpdA!Va%gxe`Q;r7Z?g(}aGTZM`;seFexpmYnRdq)3a;n_5}V~Z#QZtzK^ zIE`KSP?L4)@}3GYVfw6=KE0d2=en>5Hc#{OrXG`zpjmdQORw z{kmU4n*+LEMUR5I--JGebiY}6L|FG*M4l+n{Z`f-We4={=e6&OX+o)3MQNh8XcT2Rfcw9v zUQWG}I+A(~t=B)Pf24k$dKz&rq(jo*sed5!i1F(^@}=HLeUy4G^;+tw)L-z6Qv4Mq z{GEK-C-nhhpGWwg^xu@`Z}|ID>M(qV@%O3`_e$#B)O#rLBTlQ7KSb?~Tot(n7ze&n z&k0$62lumA+$?St-xd4B0dc>0L_8{fA)Xe`i$fTnZvsXiilj72hs>8DSt6sdMmESb z@^raXo-NOl7s<=z)$)4zRk=srCU2K_$b002@=^Jed{O>Uz9avkm=upvphT4#r9o*` zCMXGIhSIMrRF)|#lnu%@h{!Isk>4?PTiXNRqB_iLl|4HVT?SLdOGz=>M?zgeWI__ zUog5}Mw!1$eW;JcztcCy>pQ8pF%Gp+cY?AgRSL5{#_ykVlcM~$Qhz|q3Cc;KR^uPwBwP~k0>0_ z{}Z79PU?@jsR*8_*8$yU@I9hO2-D%6o9om50_F+2TvocL!^=qhIyVHkei?LfIQ1rS zzLt74Hx^-l7;q2XoO(0U^3?mO8xivL)V--|Q~#ZMH1&J@0=83+r+x;G|G@B4vVRlq zj`aa=%=(~~cT>MasrRMsrQp#ynhUOc>{642hU@FJwEO6{PY&m{sr{% zZdMha$_vVTmuIx+(|AqKcG@^PQDM1IKxO0vS)YAVzrb92SLz-v<&o5Hfxj10FCo<{so!Ze4ySj(@OksY$V&T=``75# zZ&23XFs5GwW&aIjzK^i?0j=Zmiq!tp6Ug@ijObs3ih)Ij4vkI58IP4=5E$Mv;$Oh? zTd0e0eJD3xlgcOzt@;DT$#L70&WnDWpw@KC$Aq-C&NLy9Mnnt@J-?u^a1~V zHeCYEP}!fVEO~J=hvXK=P=HJ+YG%kR56Di?}I#V0zTji;5f&{fQBV1 zizsj8hv&Sv(sYq}3~j<(Pw6sTN5cgAneK5G%`(q_1*!G*$H*GA5SrP!)PInSg!Ifw z*+-*No2iEJIf~8w7&E~M;DhpS%FUVirNyMX8d@IZQYpoEVAyMKUZ ze3UyT(j@_R?*e*?e=+3?%qSqe2CbrgA*6qne+~RDu@L-Cic|2c#7CbxfoU1=W z_`Vd+Rd~LL=gW9*MjfO{SqeY2Kv;(<;&ef}oU?`G*<7Zs#4nj@RyyE*gWY@CZ6r5& zko|MnUBvEAWg=4cuzx+fVRmn3*RDXOPn}J!oJu9jspJ=j_Cb^z%fvEL6j*Z1hKuwU4pw)1>!C*L8?OFou&ISg_n zN}(|3_rrWV?l>%Iq~r1&pg@O%!q}J3zEDnB35Q{>bu>6?;I=v@I1(I2z8QwE-|#IQ z#kb4|TVePT^mLxBph2EXFJF@!|-Wg=NYjV!FRRea>wt+9?Xe7$YGB=o^`zFc+&BE2l?JGd~X}R_YB`Z(mtm!e3rCtv{IZdigo&g za28N)&N4ie?5l&XiGA(xO)`Ab4BssF%{5{d!?&En$hXSytuuUD?51=&`&EGH7ddtt z!ge{&flI#KhEEH-(ulprd4uyN{JO`Z9bsbJ(r$eb?|Y zXK+#20V6CEdq0KQ8LO^GT#sgau3xyGc0JEI$al!_{n7BfY53k9#rL5RmNa}^p4%jZ z+d*M&@CU69^0`ClFn3AX=h8|>-`q9sDBK2jt9t^+k}qNSW*EMH!!n7iehVS==?+wHEw&8ov@cqN^jZ%t7P^`y-T^(0$ z3o>o-_z+vbu?_H*8NN!xS4TciQ##hu4&NjWBOmi24x43!X|Z#Sbc^9z&atcD+vHj2 z+2$F|cTPIi^<~d4f~03R`3RDl&vT{WyTr{n-e6$MC&x_&!ei@@#nuQX@y6$M6LVUlIB8 zD)QoaV<<;nb6!_ocV1^+FJz~C5s;S3XypAbk>1-Wtq%XQyTe@uSeJ;eTB!mZXr&gYPyAQyT`F6C0Db1aQtDHn1% zm$3g5_WzV)FHs*t>?JCdb_&Icr{ym4bDC2)mZeIihx4**DKFx@Q?*$25YkWO5`-R3 z?YWuL-^}IQ%;7huCQ&%29OBp^VZ_3-MD&wgHxI{%Ca^AI^el6E>n-;>gtmQP7 z95R8^OyD+8;FO=$!nx%WIAsf^QEE743*&bOr)*J6P*;oU1XaANg(&wTq*a|p;YtcF ztu*0ME~TB*baF^1`zN!1GMBka3sF8s`pHzL{E_kvET=^Jsd5;-WzHc_iG_3Kg#UU{OU}EU#naX_j42?KF29(Z4E#7=yO!BctVS%@&!{4 z(o@Nw5om2=8fS_t>0oYTA_x1pS?$Q7>;ti)g0|5vnK!d8Mb3V&r>JVdTqqE;fr z1{Du`t&fIk`_dcmooD2Knc}TYd&$)Pp@LY=LDm-7*pD*K^xb&@fzKdrc zo&$J@avy=d;7V}~xbjWn7O_`+U)(9~6Ay`>iYLTV;yLjW>^=T0-VyJMkEJ4Q(jx=1 zNLHXl{|odQsb+#&>Kp8yL(oiZW!J^-T!MaTF2Ogoh(pd*XTaY>uuH8ce5b-3elw4~ zUos8`*}aCswb3HpVgDUenz(~X6W`NfsWkBbTKpv56MRnI~+F-#AoJo zvY`08_!w|a;?IWkQdT0&4V#k+gf@vb*xAg)U!Ld_bAj0>4Q|kl%k$nVU=?m{-UVuzp>-`GguNNxVCAqCwLkq zQ=Q$gD|l7(phpTQ;t%vK%VY$(`?$vNu|dcD^chv8B-Mx*b!q!m<{oE#85bmNWvys0Dl2S zrw6_~SRyIFU>K%LA3H2gPi_pBE6?3>%nYEv^FH!Ps2O=QIdj?OIz zF?~qXNi!1FB)N_OmXgK$GKB+6xhEQA}E)qt!5oSlbWnLuNZ`nYcj_f19LE(N47Ll14-Lo<&S3y(@G zM$E0i9*voN?z07bz85L)6F)*Z)LT3E*1^4X^7wUOR6UCHG>To^TQ~R9!#&JHYsNA5 zoQ%Cv#$G97uaL1<%GfJq?3FU!B;zf}cvBc}D&x(?v|(brxfyRo+_y0IEzEcebFcCl zZ(;63IpZzNcndS$%DE?D?nycKq>S!RsY>Y88 zW6aAKvoOXA7-Lq(Scoy^VT^egW5tZIVu?Rd!gwPqMdCh0?;eJgm0@LNC|MawR)&(5 z`!2cVCT^{nTWjYURjy0nx)d(o!sQcZ((+IpP+>~N)GD%V7}-7rdk86vODKpi3X4S? znCdia8Kaj<;T z!Zh2)GEs|BK2Z>qxiu@u7&u3R=)f#6b#QRg4tY7dSF?LPyI*B@54*Rqdpo;#uzSyGgWK222iZNy z?&It}$?mi4zR2$H*?oiEw@*85^H%vDyC0LQnAml(8(_DD-AZ=Hu-m$6}fYC+t@wl%x!D7D7)Cbl-;Y@y@B1E*}aY3@3VV=-3PaB z`H#)YPuYEf-KW@nj@_5oeU05ev-=La@9&^oACs#p?AqA%up3~vh}{Zy}1T`A4RmVe>5q~7rsUB*KOdu9FJL2`+iW5xgU0&8bqGe zV}7rHAJV^HLOjWu|ImKJ0$Z!;Jj_y5<3)I`AiqIULrHjC@UMoCT5giF5&r`O zV`UF|k#a7q7!9RBZEdwc+E){oG?Bap3+!mbtap4=?Yq@GGxm?K9CTnoy44c|9l zhEOm^qg>d++A$CO95di$2>AhKydR+40?Zj?!M+GG*6ZSH@clPtwNYvke}OISTjFi# ztKJcRg;nj}#Cut_E08Lz;zqG2CoF(^sdToH=k|O9F3G@#oQ$@a4N_U{r*U?J_(o2MiA&yw zGGQgI463_9DK_OwWf^|=Y2To(W?&N^Vi@{|=2+vir0=A;n3XDyDC!%~jR^G(@m7Tp z*HHqc18X=TDwx+1_afR45Y_Rw$wVdZKyEYU#YW7vyTpHqA7Zt8kN6QJlzhko#WE)A z*Qsqyn9ui!@1fQMkguew7oHAJl z+w68ZRrX^QwE{NUTTtuAu)gk4eyTjD3e}=I^jhO;2iH1;THmekR}@r~pw=kYI(}HK zl571DYNikAJ&yZHeT|}%8!W~MC@4?ap_~JkG#sOUBxKFFbOC=88laAX@<;B5LQA^mm|N`2jF{Kcwb|AuazL66Z6J^Is5$ zfaw{au};|GTVyTpU5B;tOyGQloF-nEQ5lxg6a(|8(dHekwjAwu}D|pT!Jx zF6Nty#OKB3(D!@}+MX{%kN8z_3D#`;p%MBa#=#xfvp67r3C+*{z?}0URx>YwJD&qi zvjd}QCsr>*SXo|-)#ruKP+bZ+vs_$_)!9{`>@Q$#cLlTuUxe&K6|}H}a5}BYq4U zn@7Np4vGchC*VqtVMcvatQ5b(s`%HKTb~rGpru+Xek0BhzZ09pnc@}j%~!!Qe~*>$ z`OsI~4IcmB;PQ`SG_REFFt*mq)fi`UFwz#wC2}FSZm(P<=gI|GUH?|B5zk`Aeh#ba zmt}>F;N(P^ESIGiskBCel&#pH>m!XoO#k%cClLU5UR>C9ZnM@|D$?Egw zn=OU)k%%{9_C~ylE!ircNS-3kQ#xvrh4OWxWa8IC`2~2F6%@I#Z{L{t%MyhEIgZkx zT(eoO#2i;VM*$lv5p#?C_B9kIG(X^oo16pv zMw(x0Y3M|m0+^1{hJH!&(`aot-za|x z`aU8}s)^yveL?w~l_!A*Rqx|nJjUYU^BN|ih%!MFv=IYPkrrjWuv*Q7Hfc5&&r!i# zN@N-(CrVk4l!=OTaVSApEoSTbbh%U*k^o6QzrQk8QSLAEmsWYbp(?wrxZWRcYi)0D zX%2;g0jnQqv&KYwTWdTPwFCp97F9=Lvbb_`CH{+!0FSi~%JYhg!r`Kl;Cv0Gha!zy zd_(kT#T8d5$XOhopdA`=gV`gA3baL}Cf zBPvU`i-*TR!V?V80HII5!&Xj%Boa3MatDk2duQ?&O|qq3cRiVrv*+q>T)jshJO)fn z3XdO`K7M{Z45ljc7TQJiVVqZs2Q~U@1dCBjQW+A8)udQ=*`*0|V*=e!(@}Ww9EY@6 z)KxaAV)r0TjGro7IkEw?xfP*kGfwpZi+Y8bYLFgeT2fXTfCv_^EUhl9E-v(!1WM3! zuQwQR+6wDiypiTGh}9AcYD8;^sm*Pz)$w>N7W6l_cQEzFf|F$DjZ?<$D}KiBhwn@&0d~g*FSFSgiiUhzAB%~a((i*4!5snOxf4K=PFW% zmBY~Q7ZbdQ3S-z7GAY<&F{!Evs~iOrg%FWBLRHPHEf}^@Gr@=`5Zs%Rnud^8F{!(b znV2Z=6C|!e$?5ttg@U<*_%<5#Bh>()M_W6^qR3Yn^~J3i;HG$bgok5*kv6OWrWT7O zCM#}Vy!gL%UAHgqpl#m7<*QdOpE%ckFmK;=-c5IH*>dL@*Y6rX{(>!AE}Ssof-hnG zYA_*QjeQ~J)k~SyWEQU;o`&}8h))`67`9Ce+g7N zYQtdP21S@1v#uh|CS@B>KU;;(W*HO~O9T{Zx6@KjM&}5VNnH(K#FV2MSm+d?hPJcv3P6n%2YA|3fOk;wP2v*eqt z?pVN^*FUMLsXY=3PoL0o+NINS$>|FdChYo>G&}6lZlQz7tA)@LW3it$5H|0#1qek-_8Kjc2P~DixrcaCx zD6{fCcCW)rb4Yru$kC%yiYC!hR@vUS@zr#CA{4&HO`PxoxzcE(xB z9%?71AcflLf)st7*3O7Us#b6U71IOpR2$M1&jH&r@jR57;7^c{+g?t&&5+nPW=b`R z(t1(saZ6D^ywT?_^b|TBcAFK3+W@^SR4=v8#JsV#7BAQ&P4Tf{OE4CcG3wUq6DR(G zdv-T=!>Mm_>P|WJ=(nhc-`x34p1(;(J-~BKfXDv=#gjYN0FP-nD0E&PzbFq`EjY!0 zXizDosnSfddG36S)EO!CIEi@rEk?C&l)Ao0{ORNq#+qpD`);O(-55_4a=aN25fuOO!y}G z^Q>^~n>gP#1-Cm0&HxF@UFAz~L>Hwqq%7`!Su$ARb+L<}K9nwvEM>S^dSX%@m z8LKNy;^jPv-+Z6{VDVK0>o>3OTAYWaqhhwW+y%jPa^ZjGS2nHJXY}hX*fzBJ%%O%_ zo7?2hx44}4Ym!S>k1L7OIMCovw1y=I=J$n4-v~M?PfcPRaT?I?fcyi~sg{@MmzFEU zzuDr7$JRj}|0^~63W8ahg<@V$>yqL*CNPZ5xF02wDJv&jfZ-eK&df*$X+bu`0}?yD zf4_|G-=BO*Ig)%zHXJoeNTJjgK~`&!h_$wmnO5-}gl1Y`1aZCei>DgqD|dSH6v=qbm0$L~JSe5vKR__woI6RH0Of@k~I1TFE3|%y`VHy;2Ipb}K z1}hw8(qN^m0^?Oml=M&;7Ez7}kTg_dm!KdmF~UISPW;A+3tz-UKx}JiZUeFcAZFX@ zNq3H0ziiJWrTpm2OIO6He&WfPiJ(c_av!{`|1_uHPizkR`vp zJ09{ltstyh3Y!X!Ca+F@Mp`-=?D^69B&mssCQ_5Q?NMm{2$uu$Kk=>gDULpwh29sK zUlB~PmRN-Z86wOLXG%nn0*LBKnH=xJT2jS|2vZygUx_C}`z2J>N57@hr4ncQXhzl0 ztBj;ehH;BZyWB{FcFt4UjP_GI)8PZy&!P6011Dr1IUZ#XitO znnnT|Z2-FJN(&m9O(7%Wm_AAnx6Zhh?pd>{reCF8B8DZ+E-$%_=CTr*L*v)$Bs~BQT~z@uqrZUTd;K z9%`MZ)HlVG6=_;|9DNImB?tUgpgr9;4>%I&9+1x-gxR4y0y#ig$;q_g2mJs_3wsN_ zW?n|Op#9+vtPY7~s_`_XA9&a8cja5u{RiH2`<(Egy%&XQYD^{Za(Mw7ygN``Z7QiM zPwq<7+2c%SkYjjFxOfDQp|PBuW&!AI7_Z_nL;a0HPp*xb$2D5yyreVI%3rK><>tk7 zf;FdF2)Q8-3twZ60FVu$q{tjI^cQlF)(BBUr52`vG(5VB^k^itDp1*BjgZcUa9Tg* z=VOgfoL>|QpdwG4)(DxkHLVmZvGy#@nZC9@|G%)pK7U}{x`Bc9>j(5%_>4QZY`JUG zo(s2Z9va%bki>bQ8Kz%tqnA%Xl+=coywVEiMHJ#xOi~`A;5EJlKEkiBJv(tg3FRyN$F(DGg3iigqww|NE$d~m^eFN)d z;kx|f)6IR#_Vrf-YYSVak8e4@2dmcwZPSz2kCpXfhc+L+a7)+Nn_sTT?$n2mW~zLSVc8KRY9{0nvtdR zJx(H?J4cPjT#7=p$up3L=`-l}gz`eD++7v%+O#PssOea+o*~t(-i4A`Yuv?MQc_Y~60Zu!Ye`l#6HlReA8NBSdtoh_6$-Pg zxd8W^nF=H60zm^7 zm_>ny=mm3e8aW1oQ2rDZ1d4;jXpG+*3`OiLHfsb4Wg;Zzus@~_Bg}BHVw^cI&%W(} zGp{uWbjVvww||USAAVcWxyS%J9%#Z#@6xM7mn+Q zMvEc{8MA6(-9 z{Lt_Fz$Mc<{)xh7H)9zAeU8O$wver~N#!jTfh`uAcCaZ51c0nrEFg7@vKmN<^Xik7 z{F6p00tlq7mrqm%Eh#4-uMBM8oUkE85}&#dsOYnLlNb#aMn}*HD>gB#cI*~wu*k{H z3VzRoPS8()wfnTiSP6mjn3{cv`=5ZolyA?v^yJYL{hM#F9iQgDyk+7@t-tT0oyR3Y zjs7Mv-7x*}+WEhDyb?dS8T8a79!xlG(kjaBPzWlz5ZNRwRx@_Jhrq$0HU#>u*0fw= zGMNV<&6F{?p@h%oi=QqZGs%V#RpAy~i?D74!x&zX#xY&Nm^ToM#KV<#pv8}sBJH<_ zgJ6~6c74|cT6voPpx1+juca*-uZDnXwOE4Q*rZ5&)=jfMJGLbhQOCr_v^=o#q?KdZ zHcVaNDe{I(mBLt8NnYN5`N;B}HFI0)ZX6f#dz3(U<-}`G-cw)Icf~0lPrg^WE4^Lq zNf>Ao?}Khf*$AF!6>~M-=OtYnj3E?dm^N%!1ZyH-t%BsxYm%tIiiiV{%JNN^1R}J( z5DCWQ7x({08T^fM@}50}Q?8GB$`a-&3*=u$@CzIG1+^(6{*drc`CjmfeDDfdC(!K4!iw~6TjCo_4S)SF8eMjBf4 zYH8*x^~XpiSGoY^*kP{0u z*kk_ISPffWNm8j2;|R1gcLX7qV$s{t2Jw_J!l+T~cb>Jgt|VGeQeAiM*zxA?Xh?#d zC;FMM1&fRFi#_Yz3u_wvY6fQ+c$zE*92O};JVbl@%D#u#RtqNeg45D&I2cF$gWI2 zchn4=K;dj!kG7PH?HbJ&v49NGn6N=S&%DZJ#nQNhO*aS)$4XI7CKv^r6V^r+-n`H= zBML2qa)|VUe&`3GA+%$C3fn0|Lzv}LBPyH4sSh8xf4g+%+vSS)S4exlQ*OWiK=P$o zmVC=BC~;pmH&sSp-_48 ztI5{nuLu`f`xw_7bw1giiwh$S;aW>GA7|%>=~(r02-ir%eDai0%kP)B=jH`EivXhq zfKgbSm2kN&&_|OXucSF#hybZ;jub^5Hqu9nWr&d$k9J7O7(mOU;ak^L*LZ7KSKTHv z+nzz1_`?vABEceA_*O(D^&ajtpDwCkf4nE*YP2b48L3cI z7E=S@E*0o57?XL3k`w>0oMVOMm^x_5>|)W}Oh}f3H+lo8GaRUibuX`n5~Y7(ck*xcqC$Ilu=E0t)01fGmn(dwj z>ZlIJDs7m+A|s@TG+jWNI0o%la%iQQ=|`z)uSg3U(={Sla4aIaC5vv#n35u;-n2Xt z&k) zhkzXhOajwfW<-vFJO*d3<}nnG^ElPislL(hp&EmA7#`eb&5t)}hTM(ux#NBc1Md(F zy%&u@iaeY>fOGJ1(rGTwj9RUbx*m_S?p3k_CwuUt?~a0@%y>%~<885g8)VG5Qy&9A zorrT9Yh*m(TiC5Q<;l}4RkKs+r*q$Z+NQ@eGV8;x-4OUDOg5ZY{+q$Cwh6n%X0h9b z5NNhK&FfvjqJphJV!U~7Y=+oYdmM_*M#eiD8DJTCjFQ|o_c2O>P?;`gPM&nTZG%Rk ziMgYd2TjG0u>Ug!f<(#|EfQkUnnkDe_fG8sXeM;D!=|$`>c_~<$HH<{z8(&RTXZY` zUohh4hPDB#QA-T7Yzxf+pr~q|6`-L27)>+-@Fb9)1FqdVVh&i^6mW*( z1D*3OS&+PI8pL#)+3tu=t7>z8r|7D)7Vanyhg!!?m))4K&&w4YhEL)U2XHHTnKqLNSGQTM zK2Id#LD5Re#BMDcY2iDsVZ3NHT zUW|8aaFCsbt`XKIZ83_}YOw~ye2ZH7^7x?GNwZDlhouEu=42+)=N>y9 zKtU^nY_s=}!4)$~^EAC5zNB~drOVFvQs^FMLsjRrX`QtV_Pc{OY;yHpwtVR&vp1a@ zi!AA#v#hFW@JyBmw0;uZT!31LZcrQKgyG=}nh!0X-452-Z1lxtRX`(1?abW)~Z5;xWGyRmDt`3W2alwqr^0>)Ze_4upp|QZ}SG_=e z;gx2li9oKQL9BK-OxnR#VMPM9d^M3|N7zam@HsX=zdC;gc<7kL5v3}+qN3efR$tXU zYw7lRvntwFe*Ma}o}T7$J>AXT9$eaT*2J<{)4bx2jxv+$l7jKI9p#&U{=mauo6$P1 zyL(*g4CXJOFLf8&=j}$TVV|cC;ag$8vjKd!3};@?Nx0goVe1>u)3-x(VHPruisLdc zlr%$8uWuTGyDExlHTL?o1!NqB;*hCA_SDBo$R^5-V=E)5u@tffAVcd%-JS;W=_oRV zI=U?J&SkTwTs%0skZ|_svVp5__u~F5P8vS2j9HmvkI9;az9b zagMo1oSIlZsYS6^C$>U{wNw;9163$Z*d^6z7Gf=oOE4=~a0o=PKwDx=513g^t061I zO>?E_o;JR{uBN0Y9Q3%IcF`ak>^S*RHC*0x)0!d*l{@ zSWHcMz*m7N@K$4Y3wA3w;0(Ul0?yci(=#|uhjX)-qu}?hTd-j9+*4cK0f)m;K4yu$ z>!Ob7y%**OG08X_7bW{>?8cx&SOmPsaU+FOo5fu?>tInmZs-umsEdD^^q@&JmHKfF}z8#k`tM4#!!%A`UP%oxxh(~pxHo~z$PJV zeWF|^&Vco8R@-Rm2~}4MQQcfUZfreZP!*5YMtu(0(}rk6nztv?b56#hMzimtjg6Qu z%c|!2>%Dv3P1WtKngBcVtSM8@nyJrA*X`=+>FMa`>F#`T(Z*Owb3CZcM7hEyZ~s%c-8Pj{Nq~Y9}DHXnQ(Qc5q^^Vc2+p?11&xC1JEt( z_La$?+Y;C&TP;~SWxCQ7YYE*zsgexX)6xJD>!{JZ@l5C1SXBTnj>5@=J#8Z9MnH)u zsR~x7P1p^=Kg{X_Z);rJP!4)Kbb0@(`aJ7iC(J=w!$CvJUmcmANd81lscZ5COG~Sx}=5M>;M6a?@5t3F8-S5@(&AczN$$WCE;_ zpU)UXagPJ@YN_d?UqJXo=E++4defx`(74pE*cNrOOH zMM}I1nCQ~2Gj{FNgVi|o5R0@{?(Ob6ctuQ^cl0yulh7olnKPMYHr`!8me-k$2o%D5 zwPnK%ze#Y;j$u+E{b}0vn?|6XOE*VAB#5P;AZ-Uu8-`&z@Ib6T7=rB%%E`EX68h$Q;lZ z7LnCOBeB*+>?qPv{4gKkslxP!WrA^7!y9Ok)n|2eN27Zi8zYxrKC%5n-&UWD{=8so zLGmv#WYuUuU5fdyUR*(ZQ6mAGv5H9`7o_>dJ33iTU1_&ja2~t_TOAsTNXnCl%vHFb@#&8w1E%JmJ^0Z&6^@*eU9J!7hp_vmoI z{4gCz*v#_-4+VmQA8cOJHptRy2rbEFCW0dzjyc2fy;ZZ zSu$h#!iCdkF6Oq8o`>#?kKzUokd_tY1z{-3aHJF0 zda3n~AO-^2Kxwovcv*$ze-KCY|rzy_Ky=wut=E>8$`ZofM&6AV+3-0kR zoE{F}?OTH7EcH`sH^Gr?aEHMWcVnmFwOBE8KLKBp8@R8*9aMc%(WT`n;}pB2DWIr0 z^Z;p@emeD^y0qMkgYq!OgZf{nW;@KHac!JMTGu-zUXwMbfMHk8@wgOhxvh57iQy_f zF-(JR(lK(<`?d6p!s$$VhnE3;94f}SWN7zuYyL#}!JJAH2_X`FiQXCA<2xGa(er9A zY4;=Ecpey)LDSIYLs38K!aE9G{;@RqmMrO68v_^idZu4A`f~ij*`67f$gv|9bF8p` zD|ghKG-7#v(n+H%(BIAsD;nD*C#(m4Nq@E_;ezVSjMG6dkv8;a#Orm18RmqvDL#ob z6?9lD0^-&t1Wk1g8XuNsgpOR-bOB9rc2iN(J^Q zCBSmbgae7fXjJNFg(}KQiUK~DLqsHwCxq(FB&q1i%uyDWkkPVly;8<>b!YF2=!?o| zZSvJLP$sqyWN(b5SCl`DT_I=E1_^DH=<~e10&ww*jk)rU4}D3`^BKE1n&!z`h9w{! z<>}Z_BQo|fIE)dgPRsOZd4^OJB*H+H*E&>Kk*Ej-3^8R-S#Z|)!{E)BuhCB8&14h> z-Yh@IJlioWd;#6EO6ehkQoqva2WV{tMq7%xvKHaBVy#96mD;(AZHUCSf^n<@LpAFR zL^18Zk9zzfH=VZ6Q!8qsKAe^yOE9p+wBi73T-IdK7G^BYGg!blC-L{4OYQ&ZPE^On zc21tYEOF85ji1Z^hO;wPUNyd}d->FfTY6o!r}oy=mV}E6T<-E&UCWkiTp6z{@E3)h zuCf`EJC`Kfcr-CQ65@q~uNbC-u#&?y@~X)TjZ^v@M4NU1 z!Po@SZj0EMK6n5ajAr$(ZvwSvWd@AXcVnC|ccMefXdVLEv>l&MRxjo$Pe&UNz-J90 zLDN}-qs%-{h?xI5rYNx251yM4xH=4d}N9 z_kfArg0)tyxbT3>3Dl&Qre%N)Z9T#s1j`fP6z5Usl%xd`%*t{pv9Efd-rC->}?&)x8qNvAZ=sxI-k9N~ryUs!lUW8H$w>uakU`nr>4 zKsxDGH)G8E#KjqPD%sQ1&JkHjfD3`}m=k9fi=<9HMj~D~B3@B18MP2?5gCMWf1caL z_Y=X=hF+>*ORtwnv)V$}5@9jf68vLV&)m6tSFesvnb3|Dy^gRnTj;K_^w?`gb8&)j8%;O1 zl@8njgI?=fXE4FCSnMk?4lzTU&1p@$z8u9NSOuCr%h0FGN|XL^vqEV)YOT0lMz0X! zrNwNwY#gm(?4gpv{G5oS3$>KS7+R|GLv5S=luFt-fII_8Znm@DXwYqSO~q+JghbG!ytfDA^1 zx*ChzwDB;nf%PadhXk5TtLcO$TSJD87}h!)F#v(K1}^pns)BTEGgM6-ggzN#3s&-c zSi#up+>xahP1{DeXzeQ}Cm&|LXz6r0<>+I&ut)vV`a%8sIr^1Z19Ld954G_5`WjdZ zr}d#0-itk*(aP!9*T$578^cdaKbP(;HtMClB`ti3{FM&ZCWh-6afb%aAWNKvfufo= zP|Sq0ZK58o+a{Kfohgt2xofowW-yvPVuhZDV>5>nFd_$m9I{(XWRfsts&oJ%$4n9U zaR4!7bx6!_G^;~x6FNE)ZOZs8(?U(a$<}M{%{Cs?5jFyq09hKA>NE|O;3tdZk8zg4 zjm*wQ0MA7flXo1!j6oyB6IR%g};g);37!%E`}L*iJGbVh-X zC=`ogzt@jX=7@rJkRpAcLd8`eWDTa?_rv|&c9(s|H8bJPyyLEKOm^aea_1DKBl&K0 z%$TV3q`!|oCe^08x~Ak&z)@>2jfH3Qv9OEb%i%m0wD9@Zwj;P};WQSs@LmPF;&eFE zycXUs-(z@KfrF)hM@Y;+;DT+Cp(4*YJWw{rICB80nN4dBEGV4RT25LC*3T#K7^ zr~pfAD3$q00pNfW1-2jE|KJQijL3a6A9?tphh}?i9vp3)g*$Z%wwISylx$DFk$h!m zal~Jgw-Y6zHY;R|4zw{Kni6AiTtvZ}48WYEB8I@@v>g)DDq>s}CfXhd2p}YYTL)nw zP3HhRI_T(#h8Go!)Sm8w3WxczJD0d!t~qx-R(jI>gIDB-UCNZ?Lk;D{%`$QHTPMv1 z%(Qw5_SivT8U8N}OAcq)YvJ?Bo;jVK_fxd+Uin5QoMEqp_hU3uze)jn+#C;}El#*x zX6SB7h#h$b0K}g*=cf}BzyNa7;ef0NV^jbGHQs8?%-^pKbUH&wdl9@19V|Um6*m`_ zc%PJidB$H}WP$gYwNj}s$4Ga%xEqxz$ zJ}Eqiey-v0Yp5J?gKig2;kb_gVko) z150DvD2eHeuDYfR*A>xUoD~IOh@%2p6nHNkcI?F!Q>xWx^INyMrOoWKnRnrpN2<@P z?kW!FSxlp67A@xdpsy>l`wBghCDeSX^ zcNNR9>I;9``WpVX)kiA}Z98rU`WNy!Lqj5D^@XgvJn|D^Zq!~Xewg%bI|flgKdcQR zUe#>-_g9OHSrxla;!J;fR1|u%D~0f`eWp&wD^`+tMa;XnUY1^}f_G`)1$0Rq!Sdk6 z6tD!rD=6?1TfD&LUA)HTL%i0;1yi220GisKoJb6KcXPJ~l~9z{O}wv(4Mu5@`YfVAqAL^V1i!m+SH;D462>85V_$IAh=ul zKLTkGPjz%DbftGSR=hMP(2NYVEyt5WFTEBHpbRp_p(KdbE8$E*ilcv8Nn=S(<)e7S z>CHtguzTlD1hj)rNJP0>+R4TZ4Mg8!G&j+PCk5ymB+wK0*zL+24#&}bc}|zjUDH^I z7c`iy4u{j>2zl~CZm9joadKdBa6{-h5ZsUp1|%$fUwD++I0mTu2GIJ)w}t z4bQkSm3HhRsL0VBGr?3IhwBRqx%ld)LKVy(M(tU}D^8e-SxklFYMoY>Gru5&mqR$i z{>o|NP(C!Sqn3|r=urOj%0SqepPyg!az#ZbM2`b^)_DR!cfQl?2ziT&ybk4c^sdk` zFV7hcXk}tS=BTW13J1K@WN#qcRA1@9)j`za>6QMlD=*KB2D@AqcQyKmEfJT+>B802 zp*&C6E*)6;W2s<5>RKoEZfyQgfj1w;2LTcsu|?lUDIU9him6~+cg$aa7Nh)pr^~9r zTQ#e0EtiSQgJU}XYK9*-TEhy$Y z1d!M~^a)bqY+ei-Ndtn&wdIW7 z=CZ_k7?Kr*BBuXvo;Iy=YABNb9}b5tSl-zggv4)C9ZF%bEgbVW8s+I-`$SzRtS8mWj1!08dd$%7pmNVWt!{iZye zcONh|WL3E!FHeZPqP)VOABo*@izSRc(a@oeXrsv(xS^K)E81FDc6F_6-L|s2v9Y?k zsi|6?-nwGSq*Gg3PMx%3`?G=im_e9D6>_Uf*C< zRjae4LJEFKiKrmu9Y~-Ib+3f{>lgKj8Z+wBq*@xS#E`uvx!yQ-q8 zq_nBBvZ1i3q0)Q*Gf&-n|I<(1x2JOB;NXU;stv1FZ>-c{wFbaB1ew?)dhW(SI~B_x zD0fIeaUua*EM>H(Mi8q?=@-kgtQo!2TTGYkO6^Fh#oC55OWv3q>u~uBqYG-k(*C{u z@|P_&=HgIUrRkexyK(ZLa8(6doeUV3i|-yN!a7l<>g}kWE-QmIE%qaXLiKN$;#t z6}r;KG6-cP-+^Vv9e{Rw)Sec^{)IxSPzWwOIzb~Wu>7~+uB>!p@S+HA0&+uVl$+s0kpHt#CNKL`o`~D7tb;6_ngt%Iw8?eT|ch2eqP?q zrfJ(|&pvBPXZwP_nHMkdCeB%~y`!8i0+Rkh1zZJN+IIC;WCnXj&!HGA6>K&XO9 z2sG}%-303o_%U^1rLRF4=NYht0PMr~e#EUhqeQZdnH$cWOw*X#!Amf!^L_SM9Jk?; z53rIdq6rLG%mG9qife!JXEJg7k|oI>hKhqrVY=t{%+D|X)_3LY$=*F+YL^$6giI0t z_5!+Y5Oh%nx)?zFE5)4$A~>gRO}Bn5okc?XhcL@Q^@q!Ltk|BjVh_Y(F|UM15aXA2 zFHuV7s?JZ5i7(o#A65xwSX|;nm(Hat)2q;~-pfa2m4X0)vyO4PU?a1KpS1-Dq0Sof z<1R>j(8%v^nLOjdC3DZ4W83d;t8eO@I5ytu|Mn7jPx3LlIo}zW5?8#_cg|b9t7p=d z*>$yvj@F(?m3(ARLvfuo%!ZWM+dizEit$s5-Jxd>_HTU6}s z=xvVhcD8Adj#@+w1GZ`{HOAculM{dWM9EqAU1bzZLzv$RqqT=N)wNb29aa;GU>Rny zvf4777)5_ds-r&KN~PTfz(R($aY|xzIL&`@&$#^f>)-hN*;hMnwoMw_-sQ$QfA^%- zFdLY0{`|2mEltfGo#VU@Kk)d|LuZX?>}a($`7JXho;7dbuAUouCbUmUw2dcQAkf|f zG_)JE=N60Zh5!p@nbS^P+#BBSl8Co)kcrE zYs-u&YYW`Ix#K3SY-?LNY1~|&yI}2<8C$yK>&;b_4Goo5&B-53X&5(U%D9FpghM*Z za9CN9JuYz8C^Igggu=Kmg9Vz^jTt)R?Nh8d)2xF;0uVa(45dPQ*C$A>kBbv0XC8xb zp{2w)%pB|IDrlrqE10_+b6f}(ReUa+D!=k?l>PjS?f-ctl-!A*z`>)G>jeyhX*>l|gpJl%%Moe-4 zlu=B%-$6w)1+)h!b?Zx9LgOpfqAeK~r>M+&c-0|b9t2)}_ zuFmRs2b9pAD8rLlD*lKv{9;hsqQ-G}><^jNLZv0SJWZWf3voW2j)H|G=|)-4Rz>fH zDkOQFmIX%Mblkwe-2vSGkxws)3pclu=|y_8g+y>`XhK4|%>Mkc#?FS$32Qbj9@pq{ zHrI@4n>TgA4pRAHJ;MFOdn29D4cB2&fwuxcOOGobV2vS^2r!CKF-E9A@Pu9Mc2 zwC!oFr;_EL)2a2prbGLd3-R6A8IO-o-eN$8>dgmi-r#!6#T6QKz~Zd1Z|2H{MX{`f z(nRHx+u9wH1g44+Y1pWZ_7b3Y<8^(M_7F_C$YEq@=|ou52ZSgu!rcGoWtH0(G{3?)c7{s*aAT1085XM`!$Qd=uDR+RtkJXXcx64;wjt zj~U^9(Oq_^-e@UGtHm&=K)XSSwN?ft@VkCA3gPP~(-Z>LVh)iwVKW%6r@a`q8MI;x zF{|Z$isIPoRJQ0ea=5}fG))#JUte^QBXGo^66_Vh2C_<-&a~N_Xbh5KtsgDdj<9LR z*L>=HIlSZut~ApeXKAzfc1coGkZQ>q%id}DS!rz~R?!?EJKl7oI%CJ|jaL*_mc`;$$MsRh zbw{;~w9lvx6~-gg@hOuQY@fJgQ$tr(sHncG7zWF@{?+plPWsFD)tz2N~8@pgO(gCs_Nn7Hiwu9W5S3V@lLB zScyr{DbwccV|D=;;TG0(B!7LZP7sftB`1k@a9<@blqg1k!wzm zp70eFhH$lr!%E7!+E`RoXZP)^1SRyDXnEx$>RS=CUg6x7V5K#ul#fg`FN>ME<^@rV#o{xgoE(%wE@86=|=xmzKIW z*c5j`b#bD)Ek22LlM0LzoEmh=t+V3r%lb>f-Y2VLA z`+j9}=x#yH+=?_>W1($QRm(}o&Iaml(GEIZV zbucwZ0gAw7d1M~!fKL-)&W0T@@_;tHB#=nxZRLx}o4+JaQ;vLmgL=9~kB-!}*rOsD zDXx`=-9nTHI^yE&_`w3v+36c6%#el@`K9E|*Pod#V^GYIkKtYqMOgNu`sR9R_R7bS zUzQcWmfu1F&8aWSn7RSF>GW7UiN?Z8Zt6UEVaXe!HilUdOLr)OL4?2Biq91jJ3A+C zS^3d**L}2d?cp15JiJzGw>|Ym@sCebChq`}zLCTpI~8{Y6}&|&O)FU|(~EX?qRg0R zO^holv{_;Afk_243SBDgn+bIQ;upU!RTcB3h*tQ$`5qCIF*6Qag!xQdyt)lF60f7( zX}Zpa4xNxK4eeL|rfW((7K=~m8muYtO_(@wg0G}z3*HFYP~+U;tZCTSw`5(kc;EDH zo6pugeP3~O9bqGcc1`AXjY~9?6g%uVT|_3Z)G|n8)FfQofy0Y9*(Ov1XiP*SV?c8*c>S95ur0OSTsv| zZ4MH^XooGmC7q+dBNY^+Zuq$F3{{*#$%@1Wa!}$$RiYpf9A1R>p4lqwUdX}Zy>jLU zUqGQ$jUumy&FOLSNXm14aud=i=TM$7Ecaa}&ZD@JPWg8|59%>3JaHb=!Xw{DI<1~5 z(x<#G&puJxl-G|gQ}#+9nFplaOer*mI{EBQ7+J$c zH@zOAF{%AtB47BQ?R^VeTgR36%+(7?yd@!wcw8X_7$or!FJr($0&Fn0F~&B+j*Sem zjZFaauw%DP$=h)rn{B(~c?e^XDV&~N~&F0&t+3s$eWYcc8+a_tY+vZFAW!r3j z+5LIj7{33RD+xhxlJ@(3zwhx|z6V*?LJW)AwFT14O0m4j5^EefF~^JbF_WxB(L$}P z(Y{6)TUy1Q|NE+U>ERVj`kobUKrV3A#=j;(otPDKCt(}E|1RjMiUVI7BXEMd*$E?d zF&!h0Zp|cXrx-`160v_n^vOFx>t30j= zfF>l+IUEbiCOnY3gJ5MEZ7XU$hP7Q%4f)r_`Yur`QEt?S=b%0~Q@e643S!`z2);=r zQm2R2D^4`ZAp)S)D8>PGH5%72z;r1_CR$rDD)I7~)Uw73sw=6Wv?i4_tB?UBM-86XIgfgAX$|3!m#xh*T3nmOxgWdkdTW=L*+cGljnMHly z{?6^WY2qVhkPp?1x5V=VPlQV0NI&mE-(cN{S10EztH^Wh@~2d2lYb>;fgHkP&F`7<4ZfjiF=7G7|Y3hd}89si3#LZw)jsR@&Q00Z}xGK zw>QC0EHkkSWWhEQ{SgZc{l6?| zd+2LOJ=G2vUUusCz})thL$_ETHD>8x?>JR&Ni!Jrk6F)-w4`cm87^G5m@b(z9yrtY z(d~x8J*KM%>{;4uvu5!zOCsvnjE=?M^Q;JLX=Q< z6Uvt8YIJ2QDGX9_9wE4$I3NYiv^KxSgk^&^^q7YO z`E~wcXD&7Zw)V8SVX;)xXM)Bq$OEz(2ptFmPIPq|2hrLf1FWsdnzU{NbOa$pT+@v1 zuXC*i#5AJSCBxI;>ILCwFs;m^G|;)kS{4m~T(vq$0OKaKy}&i;=1967G~IYTxbDwk z2NP)_@dXU+fu)4x0IR9``k2ATWil(nn#!i?5rD=lLU+3i^hRU`D#N)P{E-qi=#h9a z1FxBU!1%>9N4l-VWZXBkvFlWKkel-Nv0qt$%+q<39~T{U`AJ1tc? z3%%C-l=KWuR$++^mc|yJm28F-OHq+kXURfxp97oC)G;?ej=vuAjT-iyKwbt~A`=Ep z!Tf04Xa^t8;Z$+6Nsrc{)ma79uGMK8+D6cyhsiGJki-OUP*8x@b_Az)%*E#TH1a`H zxRD}Ij=`H0gU8nVOgwXdqM_()R1K^4R=S+fU2zpd&nr6(`~i%3(^=?x{E#A`-G(^y zd%MsBblK>Lw6I-5!XWjgC%#>A2kPrX>%aVQXKCU3j_L-3JvaT%H{Q52(~+xRmzJfi z4VF6H#aXw_jaL*;PT!#Wyvgmw*{R8r@^L7OC6R9U56X|(Jd8aH5E?pF|>Hdx2_^TJ6-=N@B+U9{^)LCFZ;ry#b$6xapk8{ zXe!~-L~u$+Ayq|3fyy1SI$QFRH9^z#* zo~_R+v)SxUEUl=A_^EG@6Id%P!~U zLR6EE^PH*D=nLm{I1pgV&C9#*zWc5}Svv=;WLqU(`!6Z^j;x&gb-I69e9oMihF&sP zd-8hFSt)ChhNR<=t(DT)4awqOSW1B4TaXehwrR$ol_b`Zq_F9Ra(~>Y0sqK{UViyQ zue{Rq%IQ~Lp~Ipa+>%|Y;ddd;+Ur0)RG+c-k!lu;_&;+y644U#pj0PypbYwp_;PKf z8-}SdS7M&D8+h>Ez4zX;`(FIsyZfE{_TG2T9^v0Z{X_#EY@5_1?S#*O^kh*DM31?O z*22(h#Bvssm~Jl(h6h2=+N7Fr)Wd?ZXz=8px^UtC#Vr1t`!8JJkKVKR?CHgC-9tRX z5W5F^yD-^<{BcUU0HZBQ2Qhn%P<_QIP-56}m%j^Qqcyk$>9f zi16n^+LTyY@F~EbyWYLb-AXBo4*rXH1_!?K(3h5Tz_%q9#Lr2b12DrXUCer9Q4$dV zpEOS5uq)JZ#U1KoW%xZI$kK4YEQkhV0}~W0$cB*4Kc$k+E0@0~)qU=c(|6o)dhvN8 zA*}D*>~Hv|_$1c8N0@677w0Z8sJBkV*1nuMc#c$nzHMecvCejpoJfN3f!H$=Z4v63 zM3M`-WKWe`(5l;F0ozdLCuAZ0JX-1{2F-VChB z3Ym{Jk!52#AzEqXIuplrI#>?sVQogAa*UQ(5zrf!m}yWamm;YKn6Xv0JZWn7uaSi2 z9FYzM6zYTdBCP>)v?2LY`VW${C@HD9l)etsN!uUu$Xp8pIAd$%0`1b3$w-s7w5keh z2=?BpnySFD7x{|3Wo~PswIDASQq@dgBfT^otk=qeFM5{-0!eM+^b3yKB}ROV?+IO7 zaH0=v_j!ALRogt3y*|x6fBm|}s$7S~l2^?)CBRq)pyQ&ut zNWXv8nOjhpCpTYykz#g=nEvY1&UFQa8*pHmgj8rZ?LbnywXrR%pZnFes{s=QE3DLZ z5HP25lUZ*{ZathF(wNOs1V?A+cJSpE+^}ZCHQG?k!9Y1^lH2hEW>B(}wQuO`GEF+TGv1bH}z#TQ+U(3{|yNwKmqT*~ZpCyp82mZC;|11KM0p z_&!+c^R6UPSUj)N!p(mWNvuI02_nH=4Hz9B!q}mMr3Q@JuqX@u3CkE-&Z=wq>`V!h zl+&fbVBxl4A^!63fAHe(f3R45$6bHIujL=wJmGS6b? zdolPMadrjgY{i-3F=oRe)@B{Up=UadZnuol!CRCrynFyx%laTeBB9t!{N(Q+_2tA7 z-#_fr{|Bob4!8f`aNbz|U+0ZU+@Y!(U|ArR0{?a1`2UCV#(7Jfn&%-f3bO6ogA>3` z$*9c+r?d$iT!3R64~ta?MxG{&y4;}S$8hXQh|$3O2$M`kqlQ+jCD?Q}nWPBVIOtiy zQcc7R^JTKQ%#IlE21H|7V!~eF`(?B$HA(w7;CvRuTE_YJ$|X^f6&XPHB9<0oz8-g) zjJ-RLHB-_Yye<@CEVMnet$Q;t)LvRzYA-D*ElmSctX(y47MCWU#)z$+g&liUVS^@9 z>NpteAt9`#`>-XF9jZZoe&nT7XMS?q%`ctaG_y6(E|~*|Yx}EvuG?PGl8Y;DN7CfN z!u+yL?yJ6VeCq3w{a>2gyrHQ(bD%n0x4U}ZH?R4JTh6_9-RU3Qdg#-G-CHz+{?X38 z_Z@V5C5K6y+V*Fk^;EhyO?FLw^}ykaljC2w%6cS=S8thVJ<&0_=@ifcM#T-j`RCxj z>Y=gG!~Q;C2^b}=?Fdzr zqU8IemM=|O18~({QM5&ZX%PaZrl&?d^=U_q2C!+<>aoc`D1x zvayEAiJ2>g=ujw6sbUS1VZhi5sc?{F5#kI8wheX{>}ru<+m)>zf2I9&y1P;|o&T3- zdXQ}`Z*bUKqb>WdsVmjmGK`WXBQrHET@OR|nok>hX8%^g-bs2vRo#vV?!YOAx!IPS zGgZD;Pgd3b_S#`*u_@hNy}r6F?Abf$KUAp6H1Kp?sx33io~0?MD?S(fn3QI>=!@-G zkyqR0qICu9*Dcfx=1WlB=!&3z;%@?aSttg1G1~+(`n0QSVe17+p9w6*kLs!QKvNsG3~te<5B%%roQ@`ptqyRdvK<#vZ8$3 zb=$VxxI5*mrp}tm#`31Rg2`LlUax!ejYGS0Jmr3!xwy_!Q&a5u*Q%-gjn!^vK}k-k zId}ISZ&#Mh&{fqD@i&fdt@Jt_IR#m%`rHE}zMfR8vD4Racmsbr-;(c6OXqT)1y@Jo z8b0ci>z96~se%|MgB78=qhh@ru7Etbu@Yt?o47%bog6f)mJV4$%&Ui(m+4K|N7Wm~ zU|*6pHt@j41|-Ya*^p(jO)qbho9q2m-tyASqRhhF9I-ewW8pxn?A4>%s+0FID#7Sx z5QCXIv_TUJX1;?9M~^HVKfZ9}=)$obH}>}4(ARfEZ|{veHXLkfI=I0*SgN!jaM58@KPgY1_7&c5X+~rs3x1;id{#o5dRN`2to; zo2vp9Ea7wf39&{jf{e9=XAnjn@o-#41;V2vumMPXAz+2I^%TiSCZP0EiXL}W>42|m zvATy)31+L}I5Vp#!UHIRYyc?2xJ6@JdvZQ0*ZwgX1%i}^ggHwT=8wvRR`w0`YO`(J zP~XzfBG<`v{@R*qmousHXk|~0w|aHIs`1K%@(So4ttG}hSDDM!SS$2eY>!>l&~Q~# zllb-adK3TmP8P3E(QDJ_8Y@lF#$s=Eenwg~pGyEEi8}!ePxYIwlC-=OZHiWJGH%-A(xZO(D=^E=1>4s3mU z>$P`Va0hSppC81za+tYUw-2UWaD*J?d1YYW6<%|fro@`<*50-F{AV*DYAw`%?sE=9 zZk8kCv!dJq{(b%tL3a+;Bzoa{*&A8o{)e?1N9-HM80m+*D=T{{D!VHxx+@)Sw}Tx2 zer0#1ryHS__&@B<%X5<>nc*?$Z~Y3oKUb2|VmP#85dYQuJk*7N_hoqKU0@o;RG>;( zS4ukxxkBR+X`#|f>F4M9<6L>Cf-Cf06Kn~#i8-fT9p^EvB#E0L7-LLWNnaT*j0Ye* z954#0q7X$xt!Y^l9Z}_p&q!l2S+rQ2YcC0$m%#*7BYP`ga$&%;V~31p8S12^5V@h( z8V!)>8Ci zb)o1p+JhqVn5m88@^YdQ+QuyRm)H6{nPr(}g$4NzXjzk}E)5-ewJeT9Z2(M4BPKR# z9*x-k#C6=sw&I0E{IL^lZ6{zmqOJ8r&pR!T{x;2$iu;=`KKgcAwizBxpsA^fOxXNj zafpAO7q*?~*)rMMHo3XyMBC!eaGlciIpyWr{L&)+(aSo1qqVF|o9`}Kyq4d+xw)yM zvvFhB;x9jh$}(v&Djir_L>rNwd#&gfWu)x@bzwXhk6_;sbjEkCP+?cCyHJl{>UvUW zlP4?PFW%eOSY8fyG4_-WsD^mr26@V===*#rkobP7`1*V5D$^H}PgLCcuFNUV#a~Is zmKH(d8dfIq%oj>sd@rf<#MCYT2US6#7)qIH?5?ue>C^W}zyH%e73E6G<9&6>G_FSf zeW#}%l#YqC(qdua`v&F~CCI}dh?1>PCy94e`aVY%cDThqKRtIx_vyJ$Aup5!`aY%n zYiJ)>u;9+cH>hZ+-+9U(_Ba1v`8%htl$F-IV3ut0{Fl z{yhSJiTsHoNO=cyENNH^MN2LeElIv_5t@ktjb%7YKz2s4X8J}f^BcY-^(?5lV;f=d zi`3p|o3!}eK~mntB8o#T9Lf=-6`KmxE>hp1yjh$#6jzKd@!i^eI!}>Yq1&(B+b12^ z)l*#Ta&`|8O}{N|1b({E4gVL$dTG_#FnO&1YO71VklxkmrVH)uxY%CW=x&RJx?4*I z=z@B>sGi#EoD@c#mvHOjL81or!fG;Wjt#1548MTEfev^i94OFXLIn>4V?ZLF&94oB zU0 zzpklS3a`U`+#S7mn9WXk*AA5T1?f1-`wjGv_osc@Pg{HuOONB*Q66crR_Ye*n}J!x zFKEAf1?^)%#}*kjG&7;IYR{Cjii~=e!PE6v--(_;w)X1l$bKFvo4EYyJG6;o0gL~b zX1HCKej?Qn)uf$EO}QQygdPzuQn&HX3>uT^&-7X&eAsprUP04KJEa|B<>y9S zdfGa-*DdYX;A4c1igHZ${RomXB;pk*Q(Er+`;U=n+bXhy&}V zlSb%~H?0m2KVq?DlDQJm7h%>P3OUeu_*!|<=)hiS+V8Bd+!4jMW|vxUw&kY~U*AmM zdIal9VQ463&I)_bbfOOAHwAW2Bf*52q=9@$(hzG+_S9jhY8eQ;_-ZKPPl#0{btPo; zZU~&su#~t3r$S{lkkNFPJ}#Z4cE7eERg+@0TXIVZT%{krKVNUm$jQkqTwkZL`@S$S+$P+5A0(7nV6f@La+IY`v*q#fX!h*8o^#V{7v$UKBrW?G<6(&K!HFdFN2`!VWNwrl8@0Mo8%p$dnTmK-WhM z%c~-=^9vkd!?47r1sf@fD;Cn?T!AXK`o4EVG-m4jh5qs?Sc@(Ym*`T5SkiGDXi<;; zufK@STU)8YoqW=N{wKftx~c0JzkD}#i5I14Qamr?(&bmXB$rft`PGnAjBK!vEJ+9W zJ>V@gP}jVVnoSL3Pm8dv?5`4G$FQS}`I`4~VM?c|rs0>@=FHnV-54%X~Rgs%wHqCDaRfEar0i(zo7Q$3%m9A+)%U z|AkO7L7F4%Crke(l_k-PuHK!oc#@yvU-;g2e@FRV4&b*``q?s!1$0$-Sv!_VaZ+mqjJJebk)?=Vv*c&VRwW(CXh z6VH7+E(ew@+Dnjh(M~p|WbqH*(!8+*VU;cy@txXB>epkjc<^bd6H*Lp_DL^*-amlD z=z_Thuz$%~&=2I*PI`&8!12U$3h(dd4j`|MtZ0RkP%cm0Expb?OMip+Mm+x-ZVCPp z{xKNpdkp!L^R05bkl!Q7SHFg9M!7$L(|&@<(pQl01IVKV{%7D%cHd=1(rO31NGDLP zWcOQEC%vD0X6YRWjm)c^^sm76b4!=r<)&C3@Ve~6%qe{Ur}-swl9O&_jnZko^VS)fqO~~TY3`yx8b+q`BQSJM`PUa zHdaSYs#KrwXKSdeNiYdNwa=AZ4&unkS}))z57ia(Poqq#GtpD(Wd-kYPq0pYC+gP0 zZ1fcVDQJMdpR2e*y9?iZoY^$9p#5(#oYO?vsbAj83ZX1t z1UCxjhFb?G!%=uKTr*rAoJ;x(R>NOFzPGaV(kC${-GKJ~IQ*YxRj5zC^m*nbIJN*A z3$J7Q|8?j!sLxF4v#4tc^Yd9YCe^T9etBt;H{m?)JPSYslPCR>mGak@e!*Xdmhj)O z2>M|yoDtR&vfy&~9yS1H#2v?Z9D|qSVs>pm#-UQSiGOqHxAZNXOiGtFqAblgi_-;F z+INV#vW1f}3QQfJ|8-SNaJnN)+>=@0Xe)BjzGS7Cv zb;Auwb<6|j!nhEG9Rj!1#2naPEYV(re7*(R25vEe=1G?jcPq0x)Xr;f*S@Cf*Ny7N zbx-MD(EUvJww~!z^@aLseT)8jL(ni_7&eR>E*M@m{5plDq^9JiRHU?|Y)Ltr@_Nc| zjpfE>W0$et_-Rv$X}@X0G;g}ybRMhdY;%dZ+8i_wm=Bv@H(yFMrM{F_n|614X8PIm zPp5x1{qc;Bj6E4gGjGhiE2|-EB5OXoB)dBMO!n>B=d-_@{bcrY*{@mpEu)q%TXU@y z))wm)>yY&+DD=v6<^4GCb;om#ALpMeFcst!e6Bz#c(UNT1wSl!t>DdqONF-=zFqW8(F;W{7rh~G zmxtst^3C$cvq?3 zt{=Nzcm3A2SYj&4DVZ+0w&a}qjQh>f;nFwD0%g5rgJq*-KP-E#?9K9r%b#A~y#ABx zzg#gwI-Tu5Ye?uHl-7ry7Tvv`vSbKEJ`U;YZC) z&EMO2a^sUNgRN4lueGoB!PZyX2HGBIduvnmrUwHoP#WkBJlj6r{)zTS+n;TJE0`BN z98`iY1}}xOL!MAqXgG8x^vTczA*I9D(cE!&$D19OI-5I3JMZj#vh%gh*SdPTp4h9nk>z;u<*Y0^>&r^GTzUS9_3-|W!y>{=jgN1`FgJ%bS6iyFMg?~6y zIOH1&4)qT085$lsHZ(hQ?a>JuQvF{d8IV~xt zxfNUvZ8%A+iH);65dLzy4ICA5KKU4b1eXQ>Fr4b=kf#jC{5XBWCS!gLD`c}VzZPTR z$6|gR1UO%a`Sn0X3P&AGw>!V3@qPhw#58ez}y(~>sX%Vp_pIKN;Th&`BMP%>zLoj z%C)&MznL{_12KOp{B&lP%8(}IY9EgI(^;MVdoh0|D>Pup7BE@NWGD?T)F+R@c}L=mzBuu(Pv-!2wmbAY2z@=vfC_}URR3)o5INAKk# z$62JBfo0t){2jq}2x5*Mf=2cTAg@N~)yQF5yp1E|2;3Y}R3*OWP5Pdfbs>HNxy+!H z?^mKAMx_XHKF<14)+5N5-luW4$%lR8M*MALyV+K#n{S6Np4)Qm;&t<~<(%SBSHi+F z6+R!IR_7*)}kb$ z;pCF7{BFE7)W@cfpIVYbcv2rb#VA+mw^Tm0+!4gg2tUJUm(W&9!Dtrc zM)qCyw@_dFJ6xicit(p{UE*mx9d>Lz?0f9{>^b&3_B_wvnK-fL<5{c-vbjr;JJJq`%|9Bz7E@Ee)g{zlj>nHCZ89u242X1&VG;k{A8?> zoxGU4z+?Ro_YodtFX6nt8~0e2u??)5m-F?!f>&bvYGMBaYrt=EFKgvK_ByY^e%BbU z#^^VWRa6buFcTPSAK-r0i56Joj7?&Vx0(Hl*W--E6mLNL%u}=8nBITf}UuAx5I)@&Ov*E%hr&-@yFX*b^r8SOT{hlHlGmNQpAAAsY@S`mJ_>2- z03@Y*uw^mC_wqs9&pO2R;Yz4CAwPVA?`K!>tJr_%2iVi>zu^Gaee66RX7_+Yw1P9t zflM_QHVpExcbCs2{16}EqddwF^CSEyAA|1dlZ-al3&3@L1^nx0SuuN%eVg3^Zc~pP zjZOSGWUZ;}0C?3l7GRlt9ILsD{A$bt&#>=+3w?w=${xd|RbR#$?=Qi}n)n2}5qJF> z_$2#0b~*0`m-!oTqK~7OIH9%marB#ZmcpK8-@sOk3u+2y+0E=Wc8=Z7Zoqc(8|-?1 z0vz=WpM`GINq&l7!%y=w{6qZ1{3AH9@KHX`ujAMA8~BabvbhudZV3GLPuY*yKjU7- zSJ*${O08GfYy4(@3qQ+mg+TN+e!IT?&~)@<)X;u)WMq1B!q5)BZz6i!(B2stnVXH8 zLZg$jkr8k#v-*ya2q5s7o{Y@uJH?x+GZAm-jAhXo%VKU~th%PQ*0gyUq&o)Eoebh{ z(D#au>3c<<29eMo)NfZqwwpw zrK@ky?-HRR^V*swde(Gq=+qA+K{eFIqTADUulUODSh;tr<<{+<9-BC#-z#!7?;RPN z9+|uP@ObnZ~pBxz<=-+A>ivf=%0oVE)V~B4| zJ$__58l4yiQ#m%G2Zs+r(2pnK$sf{BsG$={p>+*ulPj<`seZ;hnbbDZYP#v9boGt; z84(&o{s#SQQfz}i7932QTao)*tP*pvHklJ`a!TZ6KDCT?BN0&+|Asolndme^4(rib=rMbW-cn|d z0&(yd4o}Waizn7F6hAX|4aLu(t4)w6N=q~Xm>3foP`+5KsdcSx?@-@s>c#h}+pD#m zbJLUb($&<}B_eBT8bqYOTF`Q}zq-*V>VkF8A)}}c`C>3ZGj%F|b;uVPpN)m7#E!7o zdpy5(DOLS?lW!z46OFwz zCcV@q$N1}$V*JTqeih7c2)P{GK8Z;idra8F%UEOjjtAvpl&3!?HBylHeF$^-pRhl{ zE*+D8Pa#X#AzAv3#w>-F-o}0#rdp4zu-${5VOie#I7{ETRnhMn8dT~WN_lwruzYU! zpdz^=-+9?!aa&SeAuf<9+%VQ^eP&UJbF=MwXtAG zv4rH|;oyQ~4Fwn6nvf!e2Ck8nR2Mv<$f%<2yXFE8mm(X*8O?W6=!J9}59Z78x`G!h z+=4il!ukfI;R`vOAiav#qi8A>TWFBJr{sh}F#v}=Dl1R-DcaJZ3*|g5)H%|r=sO3U zipCx8-!}+g$GJgS>FYyKAncHpCh|3f!}5X(jS`h3DE20k*0xirCdjAz24!I5TtucL zZ^H-#A_|`(T&J7Ih931X*MEb*nuCOyKD}h~uh;tBL zVny*P29IJ4RbBx5D6pP_S69#la&ZMCigf6(!beaL#Zci@j2@Xvn~rK}*&%?Syn*2` zfed$u(waOMjOi@Y8LV(72*>PMNl2+`F1!*&2%+l3a_2c$gc?;Kn>naK6xo47#!HE& zbwxVVPo!NTIT^rIkT_Ab;By}pIkq)nt=|L4_ zS;+|XP|e^$3n`iO){nPL(Oy}|C{rLs1`bA0a3w1=ET0>el`Npmt7Ln&4h$}6M?1nL zN?O!)jaRXFw(cCi3N?4AWq&s-p$p6fgd8hYk=7PRzqcouZ@%=awl=~>`eFwnEm zvyej1BF}=6o|PV;MQsR0KMa(+WS_#XqHg0=JV}u`iO3Ubq&F$DG!Z$iM#>(hWK>?M z!c^Bs)Vfkdlk4Y1{bZD@81OvDkvQ}Ge;R(q7HN~H=Nvj%-)Ge~#Mp6QA-xoCucPYBSZ zSE-G+^+LM7lSoggsaSwgOXna)M`}fX5_+x#Q|FQEMak=to0?DOyT=O*Lu;0n!dcG4 znAsTXXmd3!)NvctwE_4*1=dV6j9wFI@+yrUpS{JaG`$}vD0~Fq8_+~7$1VHh%``Ru zwcY2=ZFX(OSTu+k5W_E~rY6p9R$#apgIJDY2bdP)s#}09q_Uu54pm0a`CPKxat?WJ zTnQ%o)ch1ZdP59aR)%SC3G5uasFiiHWg{uWnk$n5;)&uP?C>ZXE6;)ah{n#Lr(daTXi%S0jUsl6Diax(s+f;}Qwyq9CvtY7 zr}@zH)CzTZ7EG9Qi24QP|6wG(c`X9_W2l($P2*ULtI6R^q8Dd4R?f{BfSW7hSlNQN zjj)9f!%M6-2^4e#1va(YgH1sXxA>F>^zxo7gl|Q5+-gx80n_VIHsG<1u-FN7%Uzg_ zQxAf#a4$15SxIC4h(%s<$29X+k=IDM7r=V6KIiU}jY>!ORI5iXfPiNZgvp^^|xM zDXvkyl;X7NCGa!Ir&Z1JL#memKCF5P;3I%-OXPR0coX@3RP_@0yy_+J>yWZd&F^~E zO8_^hUIMrgu$vP3-6Y;bemARL0>4G|68Kr9+@$7rtLi0ybE=mBZu4A#-Y8gHMen!( z3viuSJz*{j2P>77sG=$9yCy!N(=jfF#o%}Q!CLY=G2N-lzo`Xg2wsGdKUP7$N7kie z=p>Wscj~Pg;Wq}qsh=n1J!VFXIrvQ$z#qMl_B-oXDB)*!VsUVGklsf-7Ru@U@f4;8 zu#T`}p^So_NSViGZ{Y06fPh2<{d>fr&(cWg6_4|!n-uLGn5R1~>PDeH+(Cs#C&0h| E2|?EsJ^%m! literal 0 HcmV?d00001 diff --git a/views/layout.erb b/views/layout.erb index dceaadd..c0a034e 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -4,67 +4,9 @@ Sinatra Template + - - -
diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css new file mode 100644 index 0000000..3b929cd --- /dev/null +++ b/views/styles/stylesheet.css @@ -0,0 +1,58 @@ +@font-face{ + font-family: 'CalculatorFont'; + src: url('../fonts/Calculator.ttf') format('truetype'); +} + +@font-face{ + font-family: 'ButtonFont'; + src: url('open-sauce.sans-black.ttf') format('truetype'); +} +.buttons { + display: grid; + /*grid-template-columns: 50px 50px 50px 50px;*/ + grid-template-columns: repeat(4, 1fr); + gap: 2px; +} + +.button { + + padding: 20px 0px; + text-align: center; + font-family: 'ButtonFont', Arial, sans-serif; + font-size: 20px; +} + +.function { + background-color: coral; +} + +.number { + + background-color: bisque; +} + +.calculator { + + border: 5px solid; + border-radius: 5px; + background-color: black; + padding: 10px 10px; + margin: auto; + width: 60%; + + justify-content: center; + width: fit-content; +} + +.display_area { + border: 1px solid; + background-color: #9fa1a6; + margin-bottom: 10px; +} + +.display { + padding: 0px 10px; + text-align: right; + font-family: 'CalculatorFont', Arial, sans-serif; + font-size: 25px; +} From 2d80193769e454c00ec1c58a5f11b2eaa01f73bf Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Wed, 24 Jan 2024 19:16:39 +0000 Subject: [PATCH 04/36] Began defining classes --- app.rb | 23 ++++++++- libraries/calculator.rb | 32 +++++++++++++ libraries/display.rb | 59 +++++++++++++++++++++++ libraries/games.rb | 4 ++ views/basic_calculator.erb | 13 +++-- views/layout.erb | 15 +++--- views/styles/stylesheet.css | 94 +++++++++++++++++++++++++++---------- 7 files changed, 201 insertions(+), 39 deletions(-) create mode 100644 libraries/calculator.rb create mode 100644 libraries/display.rb create mode 100644 libraries/games.rb diff --git a/app.rb b/app.rb index de3543a..edcd921 100644 --- a/app.rb +++ b/app.rb @@ -1,9 +1,28 @@ require "sinatra" require "sinatra/reloader" +require "./libraries/calculator.rb" # For our calculator object. +require "./libraries/display.rb" + + get("/") do - - erb(:basic_calculator) + # We do this only once, to welcome the user : + #calc_display = new.Display + + #calc_display.add_to_history("Welcome to OMNICALC4 !!") + #calc_display.add_to_history("Have fun !!") + + redirect("/basic") + +end + +get("/basic") do + + erb(:basic_calculator) end + +#get("/basic_functions") do + +#end diff --git a/libraries/calculator.rb b/libraries/calculator.rb new file mode 100644 index 0000000..26430f2 --- /dev/null +++ b/libraries/calculator.rb @@ -0,0 +1,32 @@ +class Calculator + + def initialize + @running_amount = 0 + @decimal_used = false + end # Of method + +#--------------------------------- + + def add_numbers(number) + + if @running_amount == 0 + @running_amount = number + else + @running_amount += number + end + + end # Of method + + #--------------------------------- + + def subtract_numbers(number) + + if @running_amount == 0 + @running_amount = number + else + @running_amount -= number + end + + end # Of method + +end # Of class diff --git a/libraries/display.rb b/libraries/display.rb new file mode 100644 index 0000000..1489b86 --- /dev/null +++ b/libraries/display.rb @@ -0,0 +1,59 @@ +class Display + + def initialize + # We are going to hardcode some things here : + @history_size = 40 + + @display_history = Array.new(@history_size, " ") + + puts ("INSIDE CLASS DISPLAY :") + + end + + #------------------------------- + + def show_window(upper_range, lower_range) + + @display_history.slice(lower_range, upper_range) + + end + + #------------------------------- + + def set_display(location, display_output) + + if location < @history_size + @display_history[location] = display_output + end + + end + + #------------------------------- + + def add_to_history(message_string) + + puts "Adding to history :" + + history_counter = 0 + + while history_counter < @history_size-1 do + + temporary_string = @display_history[history_counter+1] + @display_history = temporary_string + history_counter += 1 + + end + + @display_history[@history_size-1] = message_string + + # We'll keep this here for testing purposes : + @display_history.each{ |history_string| + puts "--> #{history_string}" + } + + end + + #------------------------------- + + +end # Of class diff --git a/libraries/games.rb b/libraries/games.rb new file mode 100644 index 0000000..391b167 --- /dev/null +++ b/libraries/games.rb @@ -0,0 +1,4 @@ +class Games + + +end # Of class. diff --git a/views/basic_calculator.erb b/views/basic_calculator.erb index be09250..c908e8c 100644 --- a/views/basic_calculator.erb +++ b/views/basic_calculator.erb @@ -1,5 +1,5 @@
-
AC
+
AC
+/-
%
/
@@ -18,8 +18,11 @@
2
3
+
- -
0
-
.
-
=
+
+
0
+
.
+
=
+ +
+ diff --git a/views/layout.erb b/views/layout.erb index c0a034e..a4cdea7 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -10,14 +10,13 @@
-
00000001
-
This is a test
-
The quick brown fox jumped over the(lazy)dogs
-
00000001
-
00000001
-
00000001
-
00000001
-
00000001
+
00000001
+
+
+
BASIC
+
SCI
+
GPT
+
GAMES
<%= yield %> diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index 3b929cd..541f9da 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -7,52 +7,98 @@ font-family: 'ButtonFont'; src: url('open-sauce.sans-black.ttf') format('truetype'); } + +/* Calculator body */ + +.calculator { + + border: 5px solid; + border-radius: 5px; + background-color: black; + padding: 10px 10px; + margin: auto; + width: 60%; + + justify-content: center; + width: 400px; +} + +/* LCD display : */ + +.display_area { + border: 1px solid; + background-color: #9fa1a6; + margin-bottom: 10px; +} + +.display { +padding: 0px 10px; +text-align: right; +font-family: 'CalculatorFont', Arial, sans-serif; +font-size: 25px; +} + +/* Buttons : */ + .buttons { display: grid; - /*grid-template-columns: 50px 50px 50px 50px;*/ grid-template-columns: repeat(4, 1fr); gap: 2px; } -.button { +.bottom_row_buttons { + padding: 2px 0px; + display: grid; + grid-template-columns: 1fr 1fr 2fr; + gap: 2px; +} +.button { padding: 20px 0px; text-align: center; font-family: 'ButtonFont', Arial, sans-serif; font-size: 20px; } -.function { - background-color: coral; +.all_clear_button { + background-color: red; } .number { + background-color: whitesmoke; +} - background-color: bisque; +.function { + background-color: yellow; } -.calculator { +/* Calculator mode selection row : */ +.mode_selection_area { + padding: 10px 5px; + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 2px; +} - border: 5px solid; - border-radius: 5px; - background-color: black; - padding: 10px 10px; - margin: auto; - width: 60%; - - justify-content: center; - width: fit-content; +.mode_buttons { + padding: 20px 0px; + text-align: center; + font-family: 'ButtonFont', Arial, sans-serif; + font-size: 20px; } -.display_area { - border: 1px solid; - background-color: #9fa1a6; - margin-bottom: 10px; +.basic_button { + background-color: teal; } -.display { - padding: 0px 10px; - text-align: right; - font-family: 'CalculatorFont', Arial, sans-serif; - font-size: 25px; +.scientific_button { + background-color: blue; +} + +.gpt_button { + background-color: green; +} + +.games_button { + background-color: orangered; } From b1ec6b3c6cea63870c48e49cf862dbc43ec54074 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Thu, 25 Jan 2024 10:33:28 +0000 Subject: [PATCH 05/36] Finished Display class --- app.rb | 15 ++++++++---- libraries/display.rb | 46 ++++++++++++++++++++++++------------- views/layout.erb | 7 +++++- views/styles/stylesheet.css | 1 + 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/app.rb b/app.rb index edcd921..c68c795 100644 --- a/app.rb +++ b/app.rb @@ -1,24 +1,29 @@ require "sinatra" require "sinatra/reloader" require "./libraries/calculator.rb" # For our calculator object. -require "./libraries/display.rb" +require "./libraries/display.rb" # For our display. +@display_array = Array.new(8) +upper_display_range = 39 +lower_display_range = 32 +calc_display = Display.new get("/") do # We do this only once, to welcome the user : - #calc_display = new.Display - #calc_display.add_to_history("Welcome to OMNICALC4 !!") - #calc_display.add_to_history("Have fun !!") + calc_display.add_to_history("Welcome to OMNICALC4 !!") + calc_display.add_to_history("Have fun !!") redirect("/basic") - + end get("/basic") do + @display_array = calc_display.window(lower_display_range, upper_display_range) + erb(:basic_calculator) end diff --git a/libraries/display.rb b/libraries/display.rb index 1489b86..58e4636 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -6,13 +6,13 @@ def initialize @display_history = Array.new(@history_size, " ") - puts ("INSIDE CLASS DISPLAY :") + @test_variable = 40 end #------------------------------- - def show_window(upper_range, lower_range) + def window(lower_range, upper_range) @display_history.slice(lower_range, upper_range) @@ -20,40 +20,54 @@ def show_window(upper_range, lower_range) #------------------------------- - def set_display(location, display_output) + #def set_display(location, display_output) - if location < @history_size - @display_history[location] = display_output - end + # if location < self.history_size + # @display_history[location] = display_output + # end - end + #end #------------------------------- def add_to_history(message_string) - puts "Adding to history :" - history_counter = 0 - - while history_counter < @history_size-1 do + + while history_counter < @history_size do temporary_string = @display_history[history_counter+1] - @display_history = temporary_string + @display_history[history_counter] = temporary_string history_counter += 1 end - @display_history[@history_size-1] = message_string + @display_history[history_counter-1] = message_string + # We'll keep this here for testing purposes : - @display_history.each{ |history_string| - puts "--> #{history_string}" - } + + #counter = 0 + #@display_history.each{ |history_string| + # counter += 1 + # puts "line #{counter}--> #{history_string}" + #} end #------------------------------- + def reset_display() + + end_of_array = @display_history.length()-1 + + for counter in 0..end_of_array + + @display_history[counter] = " " + + end + + end + end # Of class diff --git a/views/layout.erb b/views/layout.erb index a4cdea7..f12a8b9 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -9,9 +9,14 @@
+
-
00000001
+ <% @display_array.each do |output| %> +
<%= output %>
+ <% end %> +
+
BASIC
SCI
diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index 541f9da..7a873ce 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -32,6 +32,7 @@ } .display { +white-space: pre; padding: 0px 10px; text-align: right; font-family: 'CalculatorFont', Arial, sans-serif; From 4b8c765100af94d9d2d54b2c3f1b9cb0dc024c59 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Thu, 25 Jan 2024 10:34:35 +0000 Subject: [PATCH 06/36] Finished Display class --- libraries/display.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/display.rb b/libraries/display.rb index 58e4636..495c2e1 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -19,6 +19,7 @@ def window(lower_range, upper_range) end #------------------------------- + #Not sure why we have this here, we will comment out for now : #def set_display(location, display_output) From c8aec5cadc73a9b10f1d058a6357cfa5b5663ed0 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Thu, 25 Jan 2024 18:55:07 +0000 Subject: [PATCH 07/36] Added All clear and equal functionality --- app.rb | 49 +++++++++++++++++++++++++++++++++++++ libraries/display.rb | 26 +++++++++++++++----- views/basic_calculator.erb | 38 ++++++++++++++-------------- views/styles/stylesheet.css | 4 +++ 4 files changed, 92 insertions(+), 25 deletions(-) diff --git a/app.rb b/app.rb index c68c795..c7ddb18 100644 --- a/app.rb +++ b/app.rb @@ -9,12 +9,15 @@ calc_display = Display.new +calc_start = true + get("/") do # We do this only once, to welcome the user : calc_display.add_to_history("Welcome to OMNICALC4 !!") calc_display.add_to_history("Have fun !!") + redirect("/basic") @@ -28,6 +31,52 @@ end +get("/:calc_input/:calc_mode") do + + calc_input = params.fetch("calc_input") + calc_mode = params.fetch("calc_mode") + + + if calc_start + + calc_display.add_to_history(calc_input) + calc_start = false + + end + + current_line = calc_display.current_line() + + case calc_input + + when "EQU" + calc_display.add_to_history(current_line) + calc_input = " " + calc_display.set_display(upper_display_range, calc_input, true) + + when "AC" + calc_display.reset_display() + + + + + + end + + calc_display.set_display(upper_display_range, calc_input) + + + case calc_mode + + when "basic" + redirect("/basic") + when "sci" + redirect("/scientific") + + end + + +end + #get("/basic_functions") do #end diff --git a/libraries/display.rb b/libraries/display.rb index 495c2e1..38c1d4d 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -19,18 +19,32 @@ def window(lower_range, upper_range) end #------------------------------- - #Not sure why we have this here, we will comment out for now : - #def set_display(location, display_output) + def set_display(location, display_output, new_line = false) - # if location < self.history_size - # @display_history[location] = display_output - # end + if location > @history_size-1 + location = @history_size-1 + end + + if !new_line + @display_history[location] += display_output + else + @display_history[location] = display_output + end + + end + + #------------------------------- + + def current_line() - #end + @display_history[@history_size-1] + + end #------------------------------- + def add_to_history(message_string) history_counter = 0 diff --git a/views/basic_calculator.erb b/views/basic_calculator.erb index c908e8c..789429e 100644 --- a/views/basic_calculator.erb +++ b/views/basic_calculator.erb @@ -1,28 +1,28 @@
-
AC
-
+/-
-
%
-
/
+
+ + + -
7
-
8
-
9
-
*
+ + + + -
4
-
5
-
6
-
-
+ + + + -
1
-
2
-
3
-
+
+ + + +
-
0
-
.
-
=
+ + +
diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index 7a873ce..f58952e 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -41,6 +41,10 @@ font-size: 25px; /* Buttons : */ +a:link, a:visited { + text-decoration: none; +} + .buttons { display: grid; grid-template-columns: repeat(4, 1fr); From 0f703fe6b1243c268649e715bce3fa4003d51025 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Sat, 27 Jan 2024 16:01:13 +0000 Subject: [PATCH 08/36] Finished basic calculator --- app.rb | 80 +++++++++++++++++++++++++------------- libraries/calculator.rb | 43 +++++++++++++------- libraries/display.rb | 8 +++- views/basic_calculator.erb | 42 +++++++++----------- 4 files changed, 105 insertions(+), 68 deletions(-) diff --git a/app.rb b/app.rb index c7ddb18..af8d0ef 100644 --- a/app.rb +++ b/app.rb @@ -1,13 +1,19 @@ require "sinatra" require "sinatra/reloader" +require "http" +require "json" +require "uri" require "./libraries/calculator.rb" # For our calculator object. require "./libraries/display.rb" # For our display. +MATH_API = "http://api.mathjs.org/v4/?expr=" + @display_array = Array.new(8) upper_display_range = 39 lower_display_range = 32 calc_display = Display.new +calc_object = Calculator.new calc_start = true @@ -17,6 +23,7 @@ calc_display.add_to_history("Welcome to OMNICALC4 !!") calc_display.add_to_history("Have fun !!") + calc_display.add_to_history(" ") redirect("/basic") @@ -31,52 +38,69 @@ end -get("/:calc_input/:calc_mode") do +get("/:input_data") do - calc_input = params.fetch("calc_input") - calc_mode = params.fetch("calc_mode") + input_array = params.fetch("input_data").split(":") + + calc_input = input_array[0] + calc_mode = input_array[1] + is_operation = input_array[2] +#------------------------- - if calc_start + case calc_input - calc_display.add_to_history(calc_input) - calc_start = false - - end + when "DIV" + calc_input = "/" - current_line = calc_display.current_line() + when "MUL" + calc_input = "*" - case calc_input + when "ADD" + calc_input = "+" - when "EQU" - calc_display.add_to_history(current_line) - calc_input = " " - calc_display.set_display(upper_display_range, calc_input, true) - - when "AC" - calc_display.reset_display() + when "SUB" + calc_input = "-" + when "PERCENT" + calc_input = "%" + when "DEC" + calc_input = "." + when "CLEAR" + calc_display.add_to_history(" ") + calc_input = "" + when "AC" + calc_display.reset_display + calc_input = "" - end + when "EQU" + output = calc_object.calculate(calc_display.history_line(upper_display_range)) + calc_display.add_to_history(output) + calc_input = "" - calc_display.set_display(upper_display_range, calc_input) + end + +#------------------------- + if calc_start + calc_display.add_to_history(calc_input) + calc_start = false + + else + calc_display.set_display(upper_display_range, calc_input) + end +#------------------------- case calc_mode - when "basic" - redirect("/basic") - when "sci" - redirect("/scientific") + when "basic" + redirect("/basic") + when "sci" + redirect("/scientific") end - end - -#get("/basic_functions") do - -#end diff --git a/libraries/calculator.rb b/libraries/calculator.rb index 26430f2..2969dc5 100644 --- a/libraries/calculator.rb +++ b/libraries/calculator.rb @@ -1,32 +1,45 @@ class Calculator def initialize - @running_amount = 0 - @decimal_used = false + @running_amount = "" + @MATH_API = "http://api.mathjs.org/v4/?expr=" end # Of method #--------------------------------- - def add_numbers(number) + def calculate(expression, precision_setting = 0) - if @running_amount == 0 - @running_amount = number - else - @running_amount += number - end + url_encoded_expression = CGI.escapeURIComponent(expression) + + calculate_url = @MATH_API + url_encoded_expression + + result = HTTP.get(calculate_url).to_s + + @running_amount = result + + result end # Of method +#--------------------------------- + + + def get_running_amount() + + @running_amount.to_s + + end + #--------------------------------- - def subtract_numbers(number) + def reset_running_amount() - if @running_amount == 0 - @running_amount = number - else - @running_amount -= number - end + @running_amount = 0 + @running_amount.to_s + + end + +#--------------------------------- - end # Of method end # Of class diff --git a/libraries/display.rb b/libraries/display.rb index 38c1d4d..64bd001 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -36,9 +36,13 @@ def set_display(location, display_output, new_line = false) #------------------------------- - def current_line() + def history_line(line_number) - @display_history[@history_size-1] + if line_number >= @history_size + @display_history[@history_size-1] + else + @display_history[line_number] + end end diff --git a/views/basic_calculator.erb b/views/basic_calculator.erb index 789429e..f534cf9 100644 --- a/views/basic_calculator.erb +++ b/views/basic_calculator.erb @@ -1,28 +1,24 @@
- - - - - - - - - - - - - - - - - - - +
AC
+
C
+
%
+
/
+
7
+
8
+
9
+
*
+
4
+
5
+
6
+
-
+
1
+
2
+
3
+
+
- - - - +
0
+
.
+
=
From 17e9dc1beb32fbde07ebbc7a102bf1654a3085b6 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Sat, 27 Jan 2024 16:05:59 +0000 Subject: [PATCH 09/36] Finished basic calculator --- libraries/display.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/display.rb b/libraries/display.rb index 64bd001..f017afc 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -6,7 +6,6 @@ def initialize @display_history = Array.new(@history_size, " ") - @test_variable = 40 end From b25a03b8ecf00d8b8c75a87121e2963c6031734f Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Sat, 27 Jan 2024 16:09:07 +0000 Subject: [PATCH 10/36] Removed unnecessary newline --- app.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app.rb b/app.rb index af8d0ef..b2ad217 100644 --- a/app.rb +++ b/app.rb @@ -23,8 +23,6 @@ calc_display.add_to_history("Welcome to OMNICALC4 !!") calc_display.add_to_history("Have fun !!") - calc_display.add_to_history(" ") - redirect("/basic") From 1f95ab9c8e8d2cefd455e1a5dd67dcee63706952 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Sun, 28 Jan 2024 03:26:43 +0000 Subject: [PATCH 11/36] Corrections to display and begin work on scientific calculator --- app.rb | 18 +++++++----------- views/basic_calculator.erb | 38 ++++++++++++++++++------------------- views/sci_calculator.erb | 0 views/styles/stylesheet.css | 1 + 4 files changed, 27 insertions(+), 30 deletions(-) create mode 100644 views/sci_calculator.erb diff --git a/app.rb b/app.rb index b2ad217..456aa90 100644 --- a/app.rb +++ b/app.rb @@ -36,9 +36,13 @@ end -get("/:input_data") do +get("/basic_calc/:input_data") do - input_array = params.fetch("input_data").split(":") + input_data = params.fetch("input_data") + + input_array = input_data.split(":") + + calc_input = " " calc_input = input_array[0] calc_mode = input_array[1] @@ -91,14 +95,6 @@ end -#------------------------- - case calc_mode - - when "basic" - redirect("/basic") - when "sci" - redirect("/scientific") - - end + redirect("/basic") end diff --git a/views/basic_calculator.erb b/views/basic_calculator.erb index f534cf9..107532d 100644 --- a/views/basic_calculator.erb +++ b/views/basic_calculator.erb @@ -1,24 +1,24 @@
-
AC
-
C
-
%
-
/
-
7
-
8
-
9
-
*
-
4
-
5
-
6
-
-
-
1
-
2
-
3
-
+
+
AC
+
C
+
%
+
/
+
7
+
8
+
9
+
*
+
4
+
5
+
6
+
-
+
1
+
2
+
3
+
+
-
0
-
.
-
=
+
0
+
.
+
=
diff --git a/views/sci_calculator.erb b/views/sci_calculator.erb new file mode 100644 index 0000000..e69de29 diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index f58952e..b7004e6 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -43,6 +43,7 @@ font-size: 25px; a:link, a:visited { text-decoration: none; + color: black; } .buttons { From fca2e7f5b5c27ce6f5bf6a3fa5c64b984b34084d Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 29 Jan 2024 00:40:56 +0000 Subject: [PATCH 12/36] Finished scientific calculator starting GPT --- app.rb | 152 ++++++++++++++++++++++++++++++++---- libraries/calculator.rb | 7 +- libraries/display.rb | 2 + views/basic_calculator.erb | 38 ++++----- views/gpt_calculator.erb | 9 +++ views/layout.erb | 8 +- views/sci_calculator.erb | 62 +++++++++++++++ views/styles/stylesheet.css | 56 ++++++++++++- 8 files changed, 292 insertions(+), 42 deletions(-) create mode 100644 views/gpt_calculator.erb diff --git a/app.rb b/app.rb index 456aa90..8f249c6 100644 --- a/app.rb +++ b/app.rb @@ -9,8 +9,8 @@ MATH_API = "http://api.mathjs.org/v4/?expr=" @display_array = Array.new(8) -upper_display_range = 39 -lower_display_range = 32 +lower_display_range = 0 +upper_display_range = 7 calc_display = Display.new calc_object = Calculator.new @@ -28,15 +28,9 @@ end -get("/basic") do +#------------------------------------------------- - @display_array = calc_display.window(lower_display_range, upper_display_range) - - erb(:basic_calculator) - -end - -get("/basic_calc/:input_data") do +get("/process_calc/:input_data") do input_data = params.fetch("input_data") @@ -46,12 +40,14 @@ calc_input = input_array[0] calc_mode = input_array[1] - is_operation = input_array[2] -#------------------------- +#------------------------------------------------- +# We will be defining out input processing here : case calc_input + # Simple math : + when "DIV" calc_input = "/" @@ -70,6 +66,64 @@ when "DEC" calc_input = "." + # Math functions : + + when "POW" + calc_input = "pow(" + + when "SQR" + calc_input = "sqrt(" + + when "NTHRT" + calc_input = "nthRoots(" + + when "LOG" + calc_input = "log(" + + when "TENPOW" + calc_input = "pow(10," + + when "NEGTENPOW" + calc_input = "pow(10,-" + + when "SIN" + calc_input = "sin(" + + when "COS" + calc_input = "cos(" + + when "TAN" + calc_input = "tan(" + + when "INVSIN" + calc_input = "asin(" + + when "INVCOS" + calc_input = "acos(" + + when "INVTAN" + calc_input = "atan(" + + when "RECIP" + calc_input = "1/" + + when "FACTOR" + calc_input = "factorial(" + + when "MOD" + calc_input = "mod(" + + + # Constants : + when "E" + calc_input = "2.718" + + when "PI" + calc_input = "3.141" + + + # "Auxilliary" buttons : + when "CLEAR" calc_display.add_to_history(" ") calc_input = "" @@ -78,14 +132,30 @@ calc_display.reset_display calc_input = "" + + # Non-numeric characters : + + when "OPENPAREN" + calc_input = "(" + + when "CLOSEPAREN" + calc_input = ")" + + when "COMMA" + calc_input = "," + +#---------------------------------------------------- + when "EQU" - output = calc_object.calculate(calc_display.history_line(upper_display_range)) + + expression = calc_display.history_line(upper_display_range) + output = calc_object.calculate(expression) calc_display.add_to_history(output) calc_input = "" end -#------------------------- +#---------------------------------------------- if calc_start calc_display.add_to_history(calc_input) calc_start = false @@ -95,6 +165,58 @@ end - redirect("/basic") +#------------------------------------------- + + case calc_mode + + when "BAS" + redirect("/basic") + + when "SCI" + redirect("/scientific") + + when "GPT" + redirect("/gpt") + + end + +end + +#------------------------------------------- + + +get("/basic") do + + upper_display_range = 39 + lower_display_range = 32 + + @display_array = calc_display.window(lower_display_range, upper_display_range) + + erb(:basic_calculator) + +end + +#------------------------------------------- + + +get("/scientific") do + + upper_display_range = 39 + lower_display_range = 32 + + @display_array = calc_display.window(lower_display_range, upper_display_range) + + erb(:sci_calculator) + +end + + +#------------------------------------------- + +get("/gpt") do + + @display_array = calc_display.window(lower_display_range, upper_display_range) + + erb(:gpt_calculator) end diff --git a/libraries/calculator.rb b/libraries/calculator.rb index 2969dc5..c851d82 100644 --- a/libraries/calculator.rb +++ b/libraries/calculator.rb @@ -3,6 +3,8 @@ class Calculator def initialize @running_amount = "" @MATH_API = "http://api.mathjs.org/v4/?expr=" + @parenthesis_status = "CLOSED" + end # Of method #--------------------------------- @@ -23,12 +25,11 @@ def calculate(expression, precision_setting = 0) #--------------------------------- - - def get_running_amount() +def get_running_amount() @running_amount.to_s - end +end #--------------------------------- diff --git a/libraries/display.rb b/libraries/display.rb index f017afc..eb5d40d 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -3,6 +3,7 @@ class Display def initialize # We are going to hardcode some things here : @history_size = 40 + @ultimate_line_length = 38 @display_history = Array.new(@history_size, " ") @@ -27,6 +28,7 @@ def set_display(location, display_output, new_line = false) if !new_line @display_history[location] += display_output + else @display_history[location] = display_output end diff --git a/views/basic_calculator.erb b/views/basic_calculator.erb index 107532d..4720373 100644 --- a/views/basic_calculator.erb +++ b/views/basic_calculator.erb @@ -1,24 +1,24 @@
-
AC
-
C
-
%
-
/
-
7
-
8
-
9
-
*
-
4
-
5
-
6
-
-
-
1
-
2
-
3
-
+
+
AC
+
C
+
%
+
/
+
7
+
8
+
9
+
*
+
4
+
5
+
6
+
-
+
1
+
2
+
3
+
+
-
0
-
.
-
=
+
0
+
.
+
=
diff --git a/views/gpt_calculator.erb b/views/gpt_calculator.erb new file mode 100644 index 0000000..4f9e4c3 --- /dev/null +++ b/views/gpt_calculator.erb @@ -0,0 +1,9 @@ +
+
+
+
CLEAR
+ + + +
+ \ No newline at end of file diff --git a/views/layout.erb b/views/layout.erb index f12a8b9..9757171 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -18,10 +18,10 @@
-
BASIC
-
SCI
-
GPT
-
GAMES
+
BASIC
+
SCI
+
GPT
+
GAMES
<%= yield %> diff --git a/views/sci_calculator.erb b/views/sci_calculator.erb index e69de29..7a0fa01 100644 --- a/views/sci_calculator.erb +++ b/views/sci_calculator.erb @@ -0,0 +1,62 @@ +
+
x^y
+
√x
+
x√y
+
AC
+
C
+ + +
e
+
π
+
log x
+
10^x
+
10^-x
+ + + +
sin x
+
cos x
+
tan x
+
sin-1 x
+
cos-1 x
+ + + +
tan-1 x
+
,
+
(
+
)
+
/
+ + + +
7
+
8
+
9
+
1/x
+
*
+ + +
4
+
5
+
6
+
x!
+
-
+ + + +
1
+
2
+
3
+
MOD
+
+
+ +
+ + +
+
0
+
.
+
%
+
=
+
diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index b7004e6..80b37ea 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -8,6 +8,7 @@ src: url('open-sauce.sans-black.ttf') format('truetype'); } + /* Calculator body */ .calculator { @@ -39,7 +40,7 @@ font-family: 'CalculatorFont', Arial, sans-serif; font-size: 25px; } -/* Buttons : */ +/* Buttons (Basic calculator) : */ a:link, a:visited { text-decoration: none; @@ -78,6 +79,59 @@ a:link, a:visited { background-color: yellow; } +/* Scientific calculator */ + +.sci_regular_buttons { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 2px; +} + +.sci_button { + padding: 20px 0px; + text-align: center; + font-family: 'ButtonFont', Arial, sans-serif; + font-size: 20px; +} + + +.sci_last_row { + padding: 2px 0px; + display: grid; + grid-template-columns: 1fr 1fr 1fr 2fr; + gap: 2px; +} + + +.math_button { + background-color: #6699cc +} + +/* Chat GPT */ + +.controls_buttons { + display: grid; + grid-template-columns: 1fr 3fr 1fr; + gap: 2px; +} + +.control_button_style { + padding: 20px 0px; + margin: 20px; + text-align: center; + font-family: 'ButtonFont', Arial, sans-serif; + font-size: 30px; +} + +.control_color { + background-color:rgb(22, 75, 50) +} + +.clear_control_color { + background-color: yellow; +} + + /* Calculator mode selection row : */ .mode_selection_area { padding: 10px 5px; From 4b0b5c36ed12adb23efb69a2ff20ad1857378250 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 29 Jan 2024 01:26:10 +0000 Subject: [PATCH 13/36] Finished GPT styling starting on response --- app.rb | 34 ++++++++++++++++++++++++++++++++++ views/gpt_calculator.erb | 11 ++++++++--- views/styles/stylesheet.css | 19 +++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/app.rb b/app.rb index 8f249c6..5653d4c 100644 --- a/app.rb +++ b/app.rb @@ -220,3 +220,37 @@ erb(:gpt_calculator) end + +#------------------------------------------- + +get("/get_response") + + open_ai_api_key = ENV.fetch("OPEN_AI_KEY") + + request_headers_hash = { + "Authorization" => "Bearer #{open_ai_api_key}", + "content-type" => "application/json" + } + + request_body_hash = { + "model" => "gpt-3.5-turbo", + "messages" => [ + { + "role" => "user", + "content" => "#{user_message}" + } + ] + } + + request_body_json = JSON.generate(request_body_hash) + + raw_response = HTTP.headers(request_headers_hash).post( + "https://api.openai.com/v1/chat/completions", + :body => request_body_json + ).to_s + + parsed_response = JSON.parse(raw_response, object_class: OpenStruct) + + gpt_response = parsed_response.choices[0].message.content + +end diff --git a/views/gpt_calculator.erb b/views/gpt_calculator.erb index 4f9e4c3..fa2e5df 100644 --- a/views/gpt_calculator.erb +++ b/views/gpt_calculator.erb @@ -3,7 +3,12 @@
CLEAR
- -
- \ No newline at end of file + +
+ + +
+ + +
diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index 80b37ea..372f95c 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -131,6 +131,25 @@ a:link, a:visited { background-color: yellow; } +textarea { + width: 100%; + border-radius: 4px; + background-color: #9fa1a6; + font-size: 25px; + font-family: 'CalculatorFont', Arial, sans-serif; + resize: none; +} + +.send_button { + width: 100%; + padding: 15px 0px; + text-align: center; + font-family: 'ButtonFont', Arial, sans-serif; + font-size: 20px; + background-color: #6699cc + +} + /* Calculator mode selection row : */ .mode_selection_area { From ff180d7879f5fc994254c7dda245550da766ad91 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 29 Jan 2024 01:48:19 +0000 Subject: [PATCH 14/36] Added method to format the GPT response. --- app.rb | 8 +++++++- libraries/display.rb | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/app.rb b/app.rb index 5653d4c..0261746 100644 --- a/app.rb +++ b/app.rb @@ -215,6 +215,8 @@ get("/gpt") do + calc_display.reset_display + @display_array = calc_display.window(lower_display_range, upper_display_range) erb(:gpt_calculator) @@ -223,7 +225,7 @@ #------------------------------------------- -get("/get_response") +post("/get_response") do open_ai_api_key = ENV.fetch("OPEN_AI_KEY") @@ -253,4 +255,8 @@ gpt_response = parsed_response.choices[0].message.content + calc_display.format_and_display(gpt_response) + + + end diff --git a/libraries/display.rb b/libraries/display.rb index eb5d40d..7adaf6b 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -89,5 +89,29 @@ def reset_display() end + #------------------------------- + + def format_and_display(string_to_format) + + line_count = 0 + + while string_to_format > @ultimate_line_length do + + line_count += 1 + + temp_string = string_to_format.slice(0, @ultimate_line_length) + + puts "Test: #{temp_string}" + + self.add_to_history(temp_string) + + string_to_format = temp_string + + end + + end + + #------------------------------- + end # Of class From c3d43a0d2f1f8db994c9eddc88fdd8de403fb646 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 29 Jan 2024 05:38:45 +0000 Subject: [PATCH 15/36] Added corrections to GPT mode --- app.rb | 124 ++++++++++++++++++++++-------------- libraries/display.rb | 23 +++++-- views/layout.erb | 19 ++++-- views/styles/stylesheet.css | 7 ++ 4 files changed, 113 insertions(+), 60 deletions(-) diff --git a/app.rb b/app.rb index 0261746..e067162 100644 --- a/app.rb +++ b/app.rb @@ -8,15 +8,21 @@ MATH_API = "http://api.mathjs.org/v4/?expr=" -@display_array = Array.new(8) +display_size = 8 lower_display_range = 0 upper_display_range = 7 +@display_array = Array.new(display_size) +@calculator_mode = "basic" + calc_display = Display.new calc_object = Calculator.new calc_start = true +#======================================================== +#======================================================== + get("/") do # We do this only once, to welcome the user : @@ -28,7 +34,7 @@ end -#------------------------------------------------- +#======================================================== get("/process_calc/:input_data") do @@ -47,7 +53,6 @@ case calc_input # Simple math : - when "DIV" calc_input = "/" @@ -165,7 +170,7 @@ end -#------------------------------------------- +#---------------------------------------------- case calc_mode @@ -182,81 +187,102 @@ end -#------------------------------------------- +#======================================================== + +post("/get_response") do + gpt_message = params.fetch("gpt_message") -get("/basic") do + calc_display.reset_display - upper_display_range = 39 - lower_display_range = 32 + open_ai_api_key = ENV.fetch("OPEN_AI_KEY") - @display_array = calc_display.window(lower_display_range, upper_display_range) + request_headers_hash = { + "Authorization" => "Bearer #{open_ai_api_key}", + "content-type" => "application/json" + } - erb(:basic_calculator) + request_body_hash = { + "model" => "gpt-3.5-turbo", + "messages" => [ + { + "role" => "user", + "content" => "#{gpt_message}" + } + ] + } + + request_body_json = JSON.generate(request_body_hash) + + raw_response = HTTP.headers(request_headers_hash).post( + "https://api.openai.com/v1/chat/completions", + :body => request_body_json + ).to_s + + parsed_response = JSON.parse(raw_response, object_class: OpenStruct) + + gpt_response = parsed_response.choices[0].message.content + + # Format and adjust the response on the screen so that it can be + # read by the user. + + calc_display.format_and_display(gpt_response) + + lower_display_range = 0 + + upper_display_range = display_size-1 + + redirect("/gpt") end -#------------------------------------------- +#======================================================== + +get("/basic") do + + upper_display_range = calc_display.get_history_size - 1 + lower_display_range = upper_display_range - display_size + + puts " mode : #{@calculator_mode}" -get("/scientific") do - upper_display_range = 39 - lower_display_range = 32 + @calculator_mode = "basic" @display_array = calc_display.window(lower_display_range, upper_display_range) - erb(:sci_calculator) + erb(:basic_calculator) end +#======================================================== -#------------------------------------------- -get("/gpt") do +get("/scientific") do + + upper_display_range = calc_display.get_history_size - 1 + lower_display_range = upper_display_range - display_size + + puts " mode : #{@calculator_mode}" - calc_display.reset_display + + @calculator_mode = "scientific" @display_array = calc_display.window(lower_display_range, upper_display_range) - erb(:gpt_calculator) + erb(:sci_calculator) end -#------------------------------------------- -post("/get_response") do - - open_ai_api_key = ENV.fetch("OPEN_AI_KEY") +#======================================================== - request_headers_hash = { - "Authorization" => "Bearer #{open_ai_api_key}", - "content-type" => "application/json" - } - - request_body_hash = { - "model" => "gpt-3.5-turbo", - "messages" => [ - { - "role" => "user", - "content" => "#{user_message}" - } - ] - } - - request_body_json = JSON.generate(request_body_hash) - - raw_response = HTTP.headers(request_headers_hash).post( - "https://api.openai.com/v1/chat/completions", - :body => request_body_json - ).to_s - - parsed_response = JSON.parse(raw_response, object_class: OpenStruct) - - gpt_response = parsed_response.choices[0].message.content +get("/gpt") do - calc_display.format_and_display(gpt_response) + @display_array = calc_display.window(lower_display_range, upper_display_range) + @calculator_mode = "gpt" + erb(:gpt_calculator) end diff --git a/libraries/display.rb b/libraries/display.rb index 7adaf6b..c165de4 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -3,7 +3,7 @@ class Display def initialize # We are going to hardcode some things here : @history_size = 40 - @ultimate_line_length = 38 + @ultimate_line_length = 40 @display_history = Array.new(@history_size, " ") @@ -95,23 +95,34 @@ def format_and_display(string_to_format) line_count = 0 - while string_to_format > @ultimate_line_length do - - line_count += 1 + while string_to_format.length > @ultimate_line_length do temp_string = string_to_format.slice(0, @ultimate_line_length) puts "Test: #{temp_string}" - self.add_to_history(temp_string) + self.set_display(line_count, temp_string) + + string_to_format = string_to_format.slice(@ultimate_line_length, string_to_format.length) - string_to_format = temp_string + line_count += 1 end + + self.set_display(line_count, string_to_format) + + line_count end #------------------------------- + def get_history_size() + + @history_size + + end + + end # Of class diff --git a/views/layout.erb b/views/layout.erb index 9757171..6332dc1 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -1,7 +1,7 @@ - Sinatra Template + OMNICALC 4 @@ -11,16 +11,25 @@
+ <% @display_array.each do |output| %> -
<%= output %>
+ + <% if @calculator_mode == "gpt" %> +
<%= output %>
+ + <% else %> +
<%= output %>
+ + <% end %> + <% end %>
-
BASIC
-
SCI
-
GPT
+
BASIC
+
SCI
+
GPT
GAMES
diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index 372f95c..6b85e26 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -150,6 +150,13 @@ textarea { } +.gpt_display { + white-space: pre; + padding: 0px 10px; + text-align: left; + font-family: 'CalculatorFont', Arial, sans-serif; + font-size: 25px; + } /* Calculator mode selection row : */ .mode_selection_area { From d9ee1141457d98e4b167495e62969e46b7037761 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 29 Jan 2024 07:59:45 +0000 Subject: [PATCH 16/36] Finished up GPT mode. Will start on Game mode. --- app.rb | 32 ++++++++++++++++++++++++-------- libraries/display.rb | 23 ++++++----------------- views/gpt_calculator.erb | 1 - 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/app.rb b/app.rb index e067162..f3472af 100644 --- a/app.rb +++ b/app.rb @@ -13,6 +13,7 @@ upper_display_range = 7 @display_array = Array.new(display_size) + @calculator_mode = "basic" calc_display = Display.new @@ -52,7 +53,8 @@ case calc_input - # Simple math : + # Basic : + when "DIV" calc_input = "/" @@ -118,6 +120,26 @@ when "MOD" calc_input = "mod(" + # GPT + when "UP" + calc_input = "" + + if lower_display_range > 0 + lower_display_range -= 1 + upper_display_range -= 1 + end + + + + when "DOWN" + calc_input = "" + + if upper_display_range < calc_display.get_history_size-1 + lower_display_range += 1 + upper_display_range += 1 + end + + # Constants : when "E" @@ -243,9 +265,6 @@ upper_display_range = calc_display.get_history_size - 1 lower_display_range = upper_display_range - display_size - - puts " mode : #{@calculator_mode}" - @calculator_mode = "basic" @@ -263,9 +282,6 @@ upper_display_range = calc_display.get_history_size - 1 lower_display_range = upper_display_range - display_size - puts " mode : #{@calculator_mode}" - - @calculator_mode = "scientific" @display_array = calc_display.window(lower_display_range, upper_display_range) @@ -279,7 +295,7 @@ get("/gpt") do - @display_array = calc_display.window(lower_display_range, upper_display_range) + @display_array = calc_display.window(lower_display_range, display_size) @calculator_mode = "gpt" diff --git a/libraries/display.rb b/libraries/display.rb index c165de4..7b56367 100644 --- a/libraries/display.rb +++ b/libraries/display.rb @@ -3,7 +3,7 @@ class Display def initialize # We are going to hardcode some things here : @history_size = 40 - @ultimate_line_length = 40 + @ultimate_line_length = 38 @display_history = Array.new(@history_size, " ") @@ -12,9 +12,9 @@ def initialize #------------------------------- - def window(lower_range, upper_range) + def window(lower_range, number_of_lines) - @display_history.slice(lower_range, upper_range) + @display_history.slice(lower_range, number_of_lines) end @@ -64,15 +64,6 @@ def add_to_history(message_string) @display_history[history_counter-1] = message_string - - # We'll keep this here for testing purposes : - - #counter = 0 - #@display_history.each{ |history_string| - # counter += 1 - # puts "line #{counter}--> #{history_string}" - #} - end #------------------------------- @@ -98,9 +89,9 @@ def format_and_display(string_to_format) while string_to_format.length > @ultimate_line_length do temp_string = string_to_format.slice(0, @ultimate_line_length) - - puts "Test: #{temp_string}" - + + temp_string = temp_string.gsub("\n"," ") + self.set_display(line_count, temp_string) string_to_format = string_to_format.slice(@ultimate_line_length, string_to_format.length) @@ -123,6 +114,4 @@ def get_history_size() end - - end # Of class diff --git a/views/gpt_calculator.erb b/views/gpt_calculator.erb index fa2e5df..5c013f2 100644 --- a/views/gpt_calculator.erb +++ b/views/gpt_calculator.erb @@ -1,7 +1,6 @@ From c40301f6126332d6fc2759efe689b55c1d5be971 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Tue, 30 Jan 2024 16:12:18 +0000 Subject: [PATCH 17/36] Tic tac toe game coding started --- app.rb | 15 ++++- libraries/games.rb | 156 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 3 deletions(-) diff --git a/app.rb b/app.rb index f3472af..ad3de8d 100644 --- a/app.rb +++ b/app.rb @@ -3,12 +3,13 @@ require "http" require "json" require "uri" -require "./libraries/calculator.rb" # For our calculator object. -require "./libraries/display.rb" # For our display. +require "./libraries/calculator.rb" +require "./libraries/display.rb" +require "./libraries/games.rb" MATH_API = "http://api.mathjs.org/v4/?expr=" -display_size = 8 +display_size = 12 lower_display_range = 0 upper_display_range = 7 @@ -18,9 +19,17 @@ calc_display = Display.new calc_object = Calculator.new +calc_tictactoe = Tic_tac_toe.new calc_start = true +#======================================================== + +#Test tic-tac-toe grid +calc_tictactoe.reset_game +calc_tictactoe.render_game + + #======================================================== #======================================================== diff --git a/libraries/games.rb b/libraries/games.rb index 391b167..db1c6f8 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -1,4 +1,160 @@ +# For Hangman : generate random word : +# https://random-word-api.vercel.app/api?words=1 + class Games + def initialize + + @max_x = 38 + @max_y = 12 + @game_display_array = Array.new(@max_y) + + self.clear_game_grid + + end + +#------------------------------------------------------- + + def render_char_at(x_loc, y_loc, render_char) + + if @max_x > x_loc && @max_y > y_loc + + temp_string = @game_display_array[y_loc] + temp_string[x_loc] = render_char + @game_display_array[y_loc] = temp_string + + end + + + end + +#------------------------------------------------------- + + def clear_game_grid() + + line_counter = 0 + + while line_counter < @max_y do + + @game_display_array[line_counter] = " "*@max_x + line_counter += 1 + + end + + end + +#------------------------------------------------------- + + def get_game_grid() + + @game_display_array + + end + end # Of class. + +#============================================================= + +class Tic_tac_toe < Games + + def initialize + + @spots = [["*","*","*"],["*","*","*"],["*","*","*"]] + @x_img = Array[" X X", " X ", " X X"] + @o_img = Array[" OO ", "O O", " OO "] + @game_board = Array[" 0000 | 1111 | 2222 ", + "------|------|------"] + @draw_x_loc = 10 + + super + + end + +#------------------------------------------------------- + + def reset_game + + @spots = [ + ["*","*","*"], + ["*","*","*"], + ["*","*","*"] + ] + + end + +#------------------------------------------------------- + + def render_game + + + row_counter = 0 + column_counter = 0 + + line_counter = 0 + + temp_string_array = Array.new(3) + temp_string_array[0] = @game_board[0] + temp_string_array[1] = @game_board[0] + temp_string_array[2] = @game_board[0] + + while row_counter != 3 do + while column_counter != 3 do + + string_to_find = column_counter.to_s*4 + + if @spots[row_counter][column_counter] == "X" + for indx in 0..2 + temp_string_array[indx] = temp_string_array[indx].sub(string_to_find, @x_img[indx]) + end + + elsif @spots[row_counter][column_counter] == "O" + for indx in 0..2 + temp_string_array[indx] = temp_string_array[indx].sub(string_to_find, @o_img[indx]) + end + + else + for indx in 0..2 + temp_string_array[indx] = temp_string_array[indx].sub(string_to_find, " ") + end + + end # Of condition block + + column_counter += 1 + + end # Of inner while ( column ) + + + for indx in 0..2 + @game_display_array[line_counter] = temp_string_array[indx] + line_counter += 1 + + end + + if row_counter < 2 + @game_display_array[line_counter] = @game_board[1] + line_counter += 1 + end + + column_counter = 0 + row_counter += 1 + + temp_string_array[0] = @game_board[0] + temp_string_array[1] = @game_board[0] + temp_string_array[2] = @game_board[0] + + end # Of outer while ( row ) + + # Let's clean up the output so that it can be displayed : + # add whitespace before and after the string so that it + # matches the display width. + # create and call : clean_up_display + + end # Of method + + + +#------------------------------------------------------- + + +end # Of class From dda87b19a3530b3072ffdeb33e82e1af6e0f4000 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:02:42 +0000 Subject: [PATCH 18/36] Finishing tic-tac-toe game --- app.rb | 2 +- libraries/games.rb | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/app.rb b/app.rb index ad3de8d..d854d28 100644 --- a/app.rb +++ b/app.rb @@ -27,7 +27,7 @@ #Test tic-tac-toe grid calc_tictactoe.reset_game -calc_tictactoe.render_game +calc_tictactoe.render_game_board #======================================================== diff --git a/libraries/games.rb b/libraries/games.rb index db1c6f8..d6cf8f9 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -28,6 +28,19 @@ def render_char_at(x_loc, y_loc, render_char) end +#------------------------------------------------------- + + def print_message(x_loc, y_loc, message) + + x_counter = 0 + + message.each_char do |individual_char| + self.render_char_at(x_loc+x_counter, y_loc, individual_char) + x_counter += 1 + end + + end + #------------------------------------------------------- def clear_game_grid() @@ -85,7 +98,7 @@ def reset_game #------------------------------------------------------- - def render_game + def render_game_board row_counter = 0 @@ -126,13 +139,13 @@ def render_game for indx in 0..2 - @game_display_array[line_counter] = temp_string_array[indx] + @game_display_array[line_counter] = " "*@draw_x_loc+temp_string_array[indx] line_counter += 1 end if row_counter < 2 - @game_display_array[line_counter] = @game_board[1] + @game_display_array[line_counter] = " "*@draw_x_loc+@game_board[1] line_counter += 1 end @@ -145,14 +158,16 @@ def render_game end # Of outer while ( row ) - # Let's clean up the output so that it can be displayed : - # add whitespace before and after the string so that it - # matches the display width. - # create and call : clean_up_display + self.print_message(25, 1, "Test message") + + @game_display_array.each do |display_line| + puts "--->#{display_line}<--" + end end # Of method + #------------------------------------------------------- From 74f1a479e455b4a13169bd5a6c814d5d1c987a78 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Wed, 31 Jan 2024 06:32:49 +0000 Subject: [PATCH 19/36] Finishing tic tac toe --- libraries/games.rb | 49 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/libraries/games.rb b/libraries/games.rb index d6cf8f9..16266cc 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -89,9 +89,9 @@ def initialize def reset_game @spots = [ - ["*","*","*"], - ["*","*","*"], - ["*","*","*"] + ["X","O","*"], + ["O","O","*"], + ["X","O","X"] ] end @@ -158,16 +158,53 @@ def render_game_board end # Of outer while ( row ) - self.print_message(25, 1, "Test message") + #self.print_message(25, 1, "Test message") @game_display_array.each do |display_line| puts "--->#{display_line}<--" end + + self.winner_result("X") end # Of method - - +#------------------------------------------------------- + + def winner_result(mark) + + is_winner = "no" + + played_array = @spots.flatten + + winning_combos = ["012","345","678","036","147","258","048","246"] + + winning_combos.each do |three_indices| + + if is_winner == "no" + counter = 0 + three_indices.each_char do |index| + + + if played_array[index.to_i] != mark + break + else + counter += 1 + end # Of condition block + + end # Of three_indices loop + + if counter == 3 + is_winner = "yes" + end # Of winner check condition + + end # Of winner condition + + end # Of winning_combos loop + + puts "Test -> #{is_winner}" + + + end # Of method #------------------------------------------------------- From 4ef6c68bbea51d31681b62947cd5c0e369612de4 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Wed, 31 Jan 2024 06:33:57 +0000 Subject: [PATCH 20/36] Finishing tic tac toe --- libraries/games.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/games.rb b/libraries/games.rb index 16266cc..77ba7b9 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -89,9 +89,9 @@ def initialize def reset_game @spots = [ - ["X","O","*"], - ["O","O","*"], - ["X","O","X"] + ["*","*","*"], + ["*","*","*"], + ["*","*","*"] ] end From aea511edb6bf0a1acf513187c9ba9a8cf9d99b7b Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Wed, 31 Jan 2024 06:43:11 +0000 Subject: [PATCH 21/36] Finishing tic tac toe --- libraries/games.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/libraries/games.rb b/libraries/games.rb index 77ba7b9..a2703d0 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -164,6 +164,8 @@ def render_game_board puts "--->#{display_line}<--" end + + self.is_draw() self.winner_result("X") end # Of method @@ -201,12 +203,25 @@ def winner_result(mark) end # Of winning_combos loop - puts "Test -> #{is_winner}" + + if self.is_draw + puts "THIS GAME IS A DRAW" + else + puts "KEEP PLAYING" + + end end # Of method #------------------------------------------------------- + def is_draw() + + played_array = @spots.flatten + + not played_array.include?("*") + + end end # Of class From 449aa469fec831613b0a6196c9128274dbd19c3c Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Wed, 31 Jan 2024 12:58:08 +0000 Subject: [PATCH 22/36] Finishing tic tac toe --- app.rb | 47 ++++++++++++++++++++ libraries/games.rb | 86 +++++++++++++++++++++++++++++++------ views/games_calculator.erb | 34 +++++++++++++++ views/layout.erb | 2 +- views/styles/stylesheet.css | 24 +++++++++++ 5 files changed, 178 insertions(+), 15 deletions(-) create mode 100644 views/games_calculator.erb diff --git a/app.rb b/app.rb index d854d28..5570c7e 100644 --- a/app.rb +++ b/app.rb @@ -311,3 +311,50 @@ erb(:gpt_calculator) end + + +#======================================================== + +get("/games") do + + calc_tictactoe.render_game_board + + calc_display.reset_display + + line_count = 0 + + game_display = calc_tictactoe.render_game_board + + game_display.each do |display_line| + + calc_display.set_display(line_count, display_line) + line_count += 1 + + end + + @calculator_mode = "games" + + @display_array = calc_display.window(0, display_size) + + + erb(:games_calculator) + +end + + +#======================================================== + +get("/process_move/:row/:column") do + + row = params.fetch("row") + column = params.fetch("column") + + if calc_tictactoe.check_spot(row, column) == "no" + calc_tictactoe.move(row, column, "X") + calc_tictactoe.computer_move + end + + + redirect("/games") + +end diff --git a/libraries/games.rb b/libraries/games.rb index a2703d0..e9b969b 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -8,6 +8,7 @@ def initialize @max_x = 38 @max_y = 12 @game_display_array = Array.new(@max_y) + @game_done = "no" self.clear_game_grid @@ -78,7 +79,7 @@ def initialize @o_img = Array[" OO ", "O O", " OO "] @game_board = Array[" 0000 | 1111 | 2222 ", "------|------|------"] - @draw_x_loc = 10 + @draw_x_loc = 5 super @@ -100,7 +101,6 @@ def reset_game def render_game_board - row_counter = 0 column_counter = 0 @@ -160,13 +160,29 @@ def render_game_board #self.print_message(25, 1, "Test message") - @game_display_array.each do |display_line| - puts "--->#{display_line}<--" + #@game_display_array.each do |display_line| + # puts "--->#{display_line}<--" + #end + + + if self.is_draw() + self.print_message(25, 4, "DRAW GAME") + @game_done = "yes" + + elsif + self.winner_result("X") == "yes" + self.print_message(25, 4, "X WINS!!") + @game_done = "yes" + + elsif + self.winner_result("O") == "yes" + self.print_message(25, 4, "O WINS!!") + @game_done = "yes" + end - self.is_draw() - self.winner_result("X") + @game_display_array end # Of method @@ -203,14 +219,8 @@ def winner_result(mark) end # Of winning_combos loop - - if self.is_draw - puts "THIS GAME IS A DRAW" - else - puts "KEEP PLAYING" - - end - + is_winner + end # Of method @@ -224,4 +234,52 @@ def is_draw() end + + +#------------------------------------------------------- + + def move(row, column, mark) + @spots[row.to_i][column.to_i] = mark + end + +#------------------------------------------------------- + + def computer_move() + + rand_num = Random.new + + random_row = rand_num.rand(0..2) + random_column = rand_num.rand(0..2) + + while self.check_spot(random_row, random_column) == "yes" && @game_done == "no" + + random_row = rand_num.rand(0..2) + random_column = rand_num.rand(0..2) + + end + + self.move(random_row, random_column, "O") + + + end + +#------------------------------------------------------- + + def check_spot(row, column) + + space_occupied = "yes" + + puts "TEST #{@spots[row.to_i][column.to_i]}" + + if @spots[row.to_i][column.to_i] == "*" + + space_occupied = "no" + + end + + space_occupied + + end + + end # Of class diff --git a/views/games_calculator.erb b/views/games_calculator.erb new file mode 100644 index 0000000..368cf06 --- /dev/null +++ b/views/games_calculator.erb @@ -0,0 +1,34 @@ +
+ +
tic-tac-toe
+
Hangman
+ + +
+ +
+ +
*
+
*
+
*
+ + +
*
+
*
+
*
+ + +
*
+
*
+
*
+ + +
+ + +
+ +
RESET
+ + +
diff --git a/views/layout.erb b/views/layout.erb index 6332dc1..4794f32 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -14,7 +14,7 @@ <% @display_array.each do |output| %> - <% if @calculator_mode == "gpt" %> + <% if @calculator_mode == "gpt" || @calculator_mode == "games" %>
<%= output %>
<% else %> diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index 6b85e26..ceb75bc 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -158,6 +158,30 @@ textarea { font-size: 25px; } +/* Games */ + +.ttt_buttons { + padding: 2px 0px; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 2px; +} + +.game_choice_buttons { + padding: 2px 0px; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2px; +} + + +.reset_game_button { + padding: 2px 0px; + display: grid; + grid-template-columns: 3fr; + gap: 2px; +} + /* Calculator mode selection row : */ .mode_selection_area { padding: 10px 5px; From ab1ccbf012cb026c4dc2909ad8653d65e072e2c4 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Wed, 31 Jan 2024 20:46:28 +0000 Subject: [PATCH 23/36] Creating hangman --- app.rb | 56 +++++++++++++++++++++++++++++++++----- libraries/games.rb | 25 +++++++++++++++++ views/games_calculator.erb | 6 ++-- 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/app.rb b/app.rb index 5570c7e..05117cd 100644 --- a/app.rb +++ b/app.rb @@ -26,6 +26,7 @@ #======================================================== #Test tic-tac-toe grid +game_selected = "tic-tac-toe" calc_tictactoe.reset_game calc_tictactoe.render_game_board @@ -317,18 +318,26 @@ get("/games") do - calc_tictactoe.render_game_board + if game_selected == "tic-tac-toe" - calc_display.reset_display + calc_tictactoe.render_game_board + + calc_display.reset_display + + line_count = 0 - line_count = 0 + game_display = calc_tictactoe.render_game_board - game_display = calc_tictactoe.render_game_board + game_display.each do |display_line| - game_display.each do |display_line| + calc_display.set_display(line_count, display_line) + line_count += 1 - calc_display.set_display(line_count, display_line) - line_count += 1 + end + + elsif game_selected == "hangman" + + puts ("HANGMAN WILL BE WRITTEN HERE....") end @@ -341,6 +350,37 @@ end +#======================================================== + +get("/reset_game") do + + if game_selected == "tic-tac-toe" + + calc_tictactoe.reset_game + calc_tictactoe.render_game_board + calc_display.reset_display + + elsif game_selected == "hangman" + + puts "HANGMAN RESET" + + end + + redirect("/games") + +end + +#======================================================== + +get ("/change_game/:game") do + + calc_display.reset_display + + game_selected = params.fetch("game") + + redirect("/games") + +end #======================================================== @@ -358,3 +398,5 @@ redirect("/games") end + +#======================================================== diff --git a/libraries/games.rb b/libraries/games.rb index e9b969b..d26347e 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -281,5 +281,30 @@ def check_spot(row, column) end +end # Of class + +#============================================================= +# |------ +# | O +# | O O +# | O +# | | +# | /|\ +# | / | \ +# | | +# | / \ +# | / \ +# | +#_______ + +class Hangman < Games + + def initialize + + @word_url = "https://random-word-api.vercel.app/api?words=1" + @hang_counter = 0 + + + end end # Of class diff --git a/views/games_calculator.erb b/views/games_calculator.erb index 368cf06..ca6f65d 100644 --- a/views/games_calculator.erb +++ b/views/games_calculator.erb @@ -1,7 +1,7 @@ @@ -28,7 +28,7 @@
-
RESET
+
RESET
From 5b6f546c022e625c306bfe1f17c942f60de132ce Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Wed, 31 Jan 2024 21:10:42 +0000 Subject: [PATCH 24/36] Began writing hangman --- libraries/games.rb | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/libraries/games.rb b/libraries/games.rb index d26347e..cd3449a 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -294,7 +294,7 @@ def check_spot(row, column) # | | # | / \ # | / \ -# | +# | _ A _ _ _ _ _ _ C _ _ _ _ _ _ #_______ class Hangman < Games @@ -307,4 +307,46 @@ def initialize end +#------------------------------------------------------- + + def draw_gallows + + puts "GALLOWS DRAWN" + + end + +#------------------------------------------------------- + + def draw_man + + case @hang_counter + when 1 + # Draw the head + puts "HEAD" + + when 2 + # Draw the body + puts "BODY" + + when 3 + # Draw the left arm + puts "LEFT ARM" + + when 4 + # Draw the right arm + puts "RIGHT ARM" + + when 5 + # Draw the left leg + puts "LEFT LEG" + + when 6 + # Finally, draw the right leg + puts "RIGHT LEG, HE IS HUNG !!" + + end + + + end + end # Of class From 75a723b7534dff509c6397ff55be6461f18f3ded Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:48:46 +0000 Subject: [PATCH 25/36] Finishing hangman --- app.rb | 40 ++++++--- libraries/games.rb | 162 ++++++++++++++++++++++++++++++++---- views/games_calculator.erb | 44 ++++++++++ views/styles/stylesheet.css | 9 +- 4 files changed, 228 insertions(+), 27 deletions(-) diff --git a/app.rb b/app.rb index 05117cd..9806815 100644 --- a/app.rb +++ b/app.rb @@ -20,13 +20,14 @@ calc_display = Display.new calc_object = Calculator.new calc_tictactoe = Tic_tac_toe.new +calc_hangman = Hangman.new calc_start = true #======================================================== #Test tic-tac-toe grid -game_selected = "tic-tac-toe" +game_choice = "tic-tac-toe" calc_tictactoe.reset_game calc_tictactoe.render_game_board @@ -318,7 +319,7 @@ get("/games") do - if game_selected == "tic-tac-toe" + if game_choice == "tic-tac-toe" calc_tictactoe.render_game_board @@ -334,17 +335,29 @@ line_count += 1 end +#.................................... + elsif game_choice == "hangman" - elsif game_selected == "hangman" + line_count = 0 - puts ("HANGMAN WILL BE WRITTEN HERE....") + #calc_hangman.pick_word + #calc_hangman.check_picked_letter("P") + game_display = calc_hangman.update_screen - end + game_display.each do |display_line| + + calc_display.set_display(line_count, display_line) + line_count += 1 + + end + + end # Of condition block for hangman @calculator_mode = "games" @display_array = calc_display.window(0, display_size) + @game_selected = game_choice erb(:games_calculator) @@ -354,15 +367,15 @@ get("/reset_game") do - if game_selected == "tic-tac-toe" + if game_choice == "tic-tac-toe" calc_tictactoe.reset_game calc_tictactoe.render_game_board calc_display.reset_display - elsif game_selected == "hangman" + elsif game_choice == "hangman" - puts "HANGMAN RESET" + calc_hangman.reset_game end @@ -376,9 +389,10 @@ calc_display.reset_display - game_selected = params.fetch("game") + @game_selected = params.fetch("game") + game_choice = @game_selected - redirect("/games") + redirect("/reset_game") end @@ -400,3 +414,9 @@ end #======================================================== + +get("/process_choice/:picked_letter") do + + puts "CHOICES PROCESSED HERE" + +end diff --git a/libraries/games.rb b/libraries/games.rb index cd3449a..5476f79 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -284,7 +284,7 @@ def check_spot(row, column) end # Of class #============================================================= -# |------ +# |-----| # | O # | O O # | O @@ -295,7 +295,7 @@ def check_spot(row, column) # | / \ # | / \ # | _ A _ _ _ _ _ _ C _ _ _ _ _ _ -#_______ +#___|___ class Hangman < Games @@ -304,6 +304,14 @@ def initialize @word_url = "https://random-word-api.vercel.app/api?words=1" @hang_counter = 0 + # For screen real estate purposes, let's limit the word length + # to 14 letters : + @ultimate_word_length = 14 + @correct_guess_counter = 0 + @picked_word = "" + @guessed_word = "" + + super end @@ -311,7 +319,14 @@ def initialize def draw_gallows - puts "GALLOWS DRAWN" + self.print_message(0,0, " |-----|") + + for count in 1..8 + self.print_message(0,count, " |") + end + + self.print_message(0,9, "==|") + end @@ -321,32 +336,147 @@ def draw_man case @hang_counter when 1 - # Draw the head - puts "HEAD" + # Draw head + self.print_message(7, 1, " O ") + self.print_message(7, 2, " O O ") + self.print_message(7, 3, " O ") when 2 - # Draw the body - puts "BODY" + # Draw the body + self.print_message(7, 4, " | ") + self.print_message(7, 5, " | ") + self.print_message(7, 6, " | ") + self.print_message(7, 7, " | ") when 3 - # Draw the left arm - puts "LEFT ARM" + # Draw the left arm + self.print_message(7, 5, " /| ") + self.print_message(7, 6, "/ | ") when 4 - # Draw the right arm - puts "RIGHT ARM" + # Draw the right arm + self.print_message(7, 5, " /|\\") + self.print_message(7, 6, "/ | \\") when 5 - # Draw the left leg - puts "LEFT LEG" + # Draw the left leg + self.print_message(7, 8, " /") + self.print_message(7, 9, "/ ") when 6 - # Finally, draw the right leg - puts "RIGHT LEG, HE IS HUNG !!" - + # Draw the right leg + self.print_message(7, 8, " / \\") + self.print_message(7, 9, "/ \\") end + end # Of method + +#------------------------------------------------------- + + def pick_word + + @picked_word = HTTP.get(@word_url).to_s + + word = @picked_word + + word_length = word.length + + while word_length > @ultimate_word_length + @picked_word = HTTP.get(@word_url) + end + + @guessed_word = "_ "*word_length + + end +#------------------------------------------------------- + + def draw_word + + self.print_message(0, 11, @guessed_word) + + end # Of method + +#------------------------------------------------------- + + def check_picked_letter(picked_letter) + + guessed_correctly = "no" + + picked_letter = picked_letter.upcase + + temporary_word = @picked_word.upcase + + counter = 0 + + temp_guessed_array = @guessed_word.split("") + + temporary_word.each_char do |letter| + + if letter == picked_letter + temp_guessed_array[counter*2] = picked_letter + guessed_correctly = "yes" + + end + + counter += 1 + + end # Of loop. + + if guessed_correctly == "no" + @hang_counter += 1 + elsif guessed_correctly == "yes" + @correct_guess_counter += 1 + end + + @guessed_word = temp_guessed_array.join + + end + +#------------------------------------------------------- + + def win_or_lose + + win_lose = "dontknow" + + # Check to see if we lost : + if @hang_counter == 6 + win_lose = "lost" + end + + if @correct_guess_counter == @picked_word.length + win_lose = "won" + end + + win_lose + + + end + +#------------------------------------------------------- + + def reset_game + + @hang_counter = 0 + @correct_guess_counter = 0 + pick_word + + end + +#------------------------------------------------------- + + def update_screen + + # Let's draw the gallows and the unlucky guy : + + draw_gallows + draw_man + draw_word + + @game_display_array + + end # Of method + end # Of class diff --git a/views/games_calculator.erb b/views/games_calculator.erb index ca6f65d..2142e1d 100644 --- a/views/games_calculator.erb +++ b/views/games_calculator.erb @@ -5,6 +5,8 @@
+ + <% if @game_selected == "tic-tac-toe" %>
@@ -25,6 +27,48 @@
+ <% elsif @game_selected == "hangman" %> + +
+ +
A
+
B
+
C
+
D
+
E
+ +
F
+
G
+
H
+
I
+
J
+ +
K
+
L
+
M
+
N
+
O
+ +
P
+
Q
+
R
+
S
+
T
+ +
U
+
V
+
W
+
X
+
Y
+ +
Z
+ + +
+ + <% end %> + +
diff --git a/views/styles/stylesheet.css b/views/styles/stylesheet.css index ceb75bc..fb5f88a 100644 --- a/views/styles/stylesheet.css +++ b/views/styles/stylesheet.css @@ -158,7 +158,7 @@ textarea { font-size: 25px; } -/* Games */ +/* Game */ .ttt_buttons { padding: 2px 0px; @@ -167,6 +167,13 @@ textarea { gap: 2px; } +.hangman_buttons { + padding: 2px 0px; + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr; + gap: 2px; +} + .game_choice_buttons { padding: 2px 0px; display: grid; From 0c2ba5e14eb806fcde24d5b03aaff7c9a247b422 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:51:13 +0000 Subject: [PATCH 26/36] Finishing hangman --- app.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app.rb b/app.rb index 9806815..33218f5 100644 --- a/app.rb +++ b/app.rb @@ -389,8 +389,7 @@ calc_display.reset_display - @game_selected = params.fetch("game") - game_choice = @game_selected + game_choice = params.fetch("game") redirect("/reset_game") From 8414c7e87938cb59b04a65ba8bd4842e1d55c8cc Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:54:14 +0000 Subject: [PATCH 27/36] Finished hangman and app for now --- app.rb | 18 +++++++++++------ libraries/games.rb | 50 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/app.rb b/app.rb index 33218f5..6696b25 100644 --- a/app.rb +++ b/app.rb @@ -319,12 +319,12 @@ get("/games") do + calc_display.reset_display + if game_choice == "tic-tac-toe" calc_tictactoe.render_game_board - calc_display.reset_display - line_count = 0 game_display = calc_tictactoe.render_game_board @@ -340,10 +340,10 @@ line_count = 0 - #calc_hangman.pick_word - #calc_hangman.check_picked_letter("P") game_display = calc_hangman.update_screen + won_or_lost = calc_hangman.win_or_lose + game_display.each do |display_line| calc_display.set_display(line_count, display_line) @@ -352,6 +352,7 @@ end end # Of condition block for hangman +#.................................... @calculator_mode = "games" @@ -367,11 +368,12 @@ get("/reset_game") do + calc_display.reset_display + if game_choice == "tic-tac-toe" calc_tictactoe.reset_game calc_tictactoe.render_game_board - calc_display.reset_display elsif game_choice == "hangman" @@ -416,6 +418,10 @@ get("/process_choice/:picked_letter") do - puts "CHOICES PROCESSED HERE" + picked_letter = params.fetch("picked_letter") + + calc_hangman.check_picked_letter(picked_letter) + + redirect("/games") end diff --git a/libraries/games.rb b/libraries/games.rb index 5476f79..1bab2ae 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -95,6 +95,8 @@ def reset_game ["*","*","*"] ] + @game_done = "no" + end #------------------------------------------------------- @@ -269,7 +271,6 @@ def check_spot(row, column) space_occupied = "yes" - puts "TEST #{@spots[row.to_i][column.to_i]}" if @spots[row.to_i][column.to_i] == "*" @@ -380,13 +381,25 @@ def pick_word word = @picked_word + word = word.gsub(/[^a-z ]/i, '') + + @picked_word = word + word_length = word.length while word_length > @ultimate_word_length @picked_word = HTTP.get(@word_url) end - @guessed_word = "_ "*word_length + temp_string = "" + + word.each_char do |letter| + + temp_string += "_" + + end + + @guessed_word = temp_string end @@ -408,30 +421,29 @@ def check_picked_letter(picked_letter) picked_letter = picked_letter.upcase temporary_word = @picked_word.upcase + temp_guessed_word = @guessed_word - counter = 0 - - temp_guessed_array = @guessed_word.split("") - + array_counter = 0 temporary_word.each_char do |letter| if letter == picked_letter - temp_guessed_array[counter*2] = picked_letter + temp_guessed_word[array_counter] = picked_letter + @correct_guess_counter += 1 guessed_correctly = "yes" - + end - - counter += 1 + array_counter += 1 end # Of loop. + #........................ + + @guessed_word = temp_guessed_word + if guessed_correctly == "no" @hang_counter += 1 - elsif guessed_correctly == "yes" - @correct_guess_counter += 1 end - @guessed_word = temp_guessed_array.join end @@ -444,10 +456,17 @@ def win_or_lose # Check to see if we lost : if @hang_counter == 6 win_lose = "lost" + @game_done = "yes" + self.print_message(10, 5, "Sorry,") + self.print_message(10, 6, "You were HANGED!!") end if @correct_guess_counter == @picked_word.length win_lose = "won" + @game_done = "yes" + self.print_message(10, 5, "Congratulations,") + self.print_message(10, 6, "No hanging this time!!") + end win_lose @@ -463,6 +482,11 @@ def reset_game @correct_guess_counter = 0 pick_word + self.clear_game_grid + + @game_done = "no" + + end #------------------------------------------------------- From e378d9c303d7122b107b9a8e917cce79317d038e Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:56:43 +0000 Subject: [PATCH 28/36] Finished with hangman and OMNICALC4 app for now --- libraries/games.rb | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/libraries/games.rb b/libraries/games.rb index 1bab2ae..0bf163b 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -285,18 +285,7 @@ def check_spot(row, column) end # Of class #============================================================= -# |-----| -# | O -# | O O -# | O -# | | -# | /|\ -# | / | \ -# | | -# | / \ -# | / \ -# | _ A _ _ _ _ _ _ C _ _ _ _ _ _ -#___|___ + class Hangman < Games From b7a349df48acd903a221d0f09732db6d56cb871d Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Fri, 2 Feb 2024 00:38:33 -0500 Subject: [PATCH 29/36] Updated README.md --- README.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a83f6f8..ffe5c58 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,21 @@ -# sinatra-template +# OMNICALC 4 -Use this repository to create new Sinatra apps. +This app is an extension of the OMNICALC lessons from previous modules. -Optionally, to use `ActiveRecord` for database operations, add to the `app.rb`: +It features: -```ruby -require "sinatra/activerecord" -``` +* Basic and scientific calculators -And in the `config/environment.rb` file add this code block: +* GPT Chat -```ruby -configure do - # setup a database connection - set(:database, { adapter: "sqlite3", database: "db/development.sqlite3" }) -end -``` +* Hangman and Tic-tac-toe games + +Note : +I wrote this app mostly to see the limitations and strengths of the Ruby language. +It still needs work in a couple of areas : + + * Some of the code should be refactored. + + * Maybe use a different font, so that the images in the games line up better. + +I hope you have as much fun with this app as I had writing it. From ee2c7251519b542a31a94906968250c93916e4b7 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Fri, 2 Feb 2024 00:50:11 -0500 Subject: [PATCH 30/36] Update README.md --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index ffe5c58..4978f9f 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,36 @@ It still needs work in a couple of areas : * Maybe use a different font, so that the images in the games line up better. I hope you have as much fun with this app as I had writing it. + +# How to use the app : + +Basic calculator : +You should be able to use this calculator like a normal calculator. + +Scientific calculator : +This can also be used as a normal calculator with an exception: +The higher-math functions( exponent, factorial ) calls functions from mathjs api. +Here's the documentation : https://mathjs.org/docs/reference/functions.html + +Chat GPT +Ask a question in the text box below the controls and click "SEND". + +Use the up and down arrows to scroll through the answer. + +Games : + +Hangman +Click on the letter that you want to guess. +If the guess is incorrect, a portion of the man will be drawn, if the man is completely drawn, then the game is over. +If you correctly guess the word, then you win and the game is over. + +Click the "RESET" button for a new game. + +Tic-tac-toe +Click any of the yellow buttons below the display, corresponding to the position on the board +that you would like to draw your 'X'. +The computer will automatically move. + +Clicking "RESET" will also reset this game. + + From 5a816a5560b7478e499aa09aa73386e45e02298e Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Fri, 2 Feb 2024 00:51:02 -0500 Subject: [PATCH 31/36] Update README.md --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4978f9f..1c8d051 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,18 @@ I hope you have as much fun with this app as I had writing it. # How to use the app : Basic calculator : + You should be able to use this calculator like a normal calculator. Scientific calculator : + This can also be used as a normal calculator with an exception: The higher-math functions( exponent, factorial ) calls functions from mathjs api. -Here's the documentation : https://mathjs.org/docs/reference/functions.html +Here's the documentation : +https://mathjs.org/docs/reference/functions.html Chat GPT + Ask a question in the text box below the controls and click "SEND". Use the up and down arrows to scroll through the answer. @@ -38,13 +42,15 @@ Use the up and down arrows to scroll through the answer. Games : Hangman + Click on the letter that you want to guess. If the guess is incorrect, a portion of the man will be drawn, if the man is completely drawn, then the game is over. If you correctly guess the word, then you win and the game is over. Click the "RESET" button for a new game. -Tic-tac-toe +Tic-tac-toe + Click any of the yellow buttons below the display, corresponding to the position on the board that you would like to draw your 'X'. The computer will automatically move. From d48613ba1bb4848bfe259643a588e43b583d2227 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Fri, 2 Feb 2024 03:36:25 -0500 Subject: [PATCH 32/36] Update render.yaml --- render.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render.yaml b/render.yaml index 814a0b4..b99513d 100644 --- a/render.yaml +++ b/render.yaml @@ -1,6 +1,6 @@ services: - type: web - name: MYAPPNAME # the name of this service, eg hello-world + name: omnicalc4 # the name of this service, eg hello-world env: ruby # this app is written in ruby plan: free # make sure to set this to free or you'll get billed $$$ buildCommand: "./bin/render-build.sh" # # we already created these two files for you From d6e879bc1649e3c3177e93197d6eaaf4a4d14643 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Fri, 2 Feb 2024 04:23:12 -0500 Subject: [PATCH 33/36] Update README.md --- README.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 1c8d051..8d4c846 100644 --- a/README.md +++ b/README.md @@ -23,38 +23,43 @@ I hope you have as much fun with this app as I had writing it. # How to use the app : Basic calculator : +------------------ You should be able to use this calculator like a normal calculator. Scientific calculator : +----------------------- This can also be used as a normal calculator with an exception: The higher-math functions( exponent, factorial ) calls functions from mathjs api. Here's the documentation : https://mathjs.org/docs/reference/functions.html -Chat GPT +Chat GPT : +---------- -Ask a question in the text box below the controls and click "SEND". +* Ask a question in the text box below the controls and click "SEND". -Use the up and down arrows to scroll through the answer. +* Use the up and down arrows to scroll through the answer. -Games : +Games ( Hangman ) : +------------------- -Hangman +* Click on the letter that you want to guess. + +* If the guess is incorrect, a portion of the man will be drawn, if the man is completely drawn, then the game is over. -Click on the letter that you want to guess. -If the guess is incorrect, a portion of the man will be drawn, if the man is completely drawn, then the game is over. -If you correctly guess the word, then you win and the game is over. +* If you correctly guess the word, then you win and the game is over. -Click the "RESET" button for a new game. +* Click the "RESET" button for a new game. -Tic-tac-toe +Games ( Tic-tac-toe ) : +----------------------- -Click any of the yellow buttons below the display, corresponding to the position on the board -that you would like to draw your 'X'. -The computer will automatically move. +* Click any of the yellow buttons below the display, corresponding to the position on the board that you would like to draw your 'X'. -Clicking "RESET" will also reset this game. +* The computer will automatically move. + +* Clicking "RESET" will also reset this game. From d86f380e28a1d3ca86f1b2cdc79442a310c82d94 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Fri, 2 Feb 2024 04:23:59 -0500 Subject: [PATCH 34/36] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8d4c846..d65be20 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Scientific calculator : This can also be used as a normal calculator with an exception: The higher-math functions( exponent, factorial ) calls functions from mathjs api. + Here's the documentation : https://mathjs.org/docs/reference/functions.html From 946ee28c215f78c676efce93b22dda7ea6739a06 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:26:20 +0000 Subject: [PATCH 35/36] Added HTTP gem --- Gemfile | 1 + Gemfile.lock | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/Gemfile b/Gemfile index 8017805..4d5e956 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ ruby "3.2.1" gem "sinatra" gem "sinatra-contrib" +gem "http" # Use Puma as the app server gem "puma", "~> 5.0" diff --git a/Gemfile.lock b/Gemfile.lock index fc6078a..8e17850 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -40,6 +40,7 @@ GEM rexml debug_inspector (1.1.0) diff-lcs (1.5.0) + domain_name (0.6.20240107) draft_matchers (0.0.2) capybara color_namer @@ -51,6 +52,10 @@ GEM ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) faraday-retry (1.0.3) + ffi (1.16.3) + ffi-compiler (1.0.1) + ffi (>= 1.0.0) + rake grade_runner (0.0.9) activesupport (>= 2.3.5) faraday-retry (~> 1.0.3) @@ -58,8 +63,19 @@ GEM oj (~> 3.13.12) rake (~> 13) hashdiff (1.0.1) + http (5.1.1) + addressable (~> 2.8) + http-cookie (~> 1.0) + http-form_data (~> 2.2) + llhttp-ffi (~> 0.4.0) + http-cookie (1.0.5) + domain_name (~> 0.5) + http-form_data (2.3.0) i18n (1.12.0) concurrent-ruby (~> 1.0) + llhttp-ffi (0.4.0) + ffi-compiler (~> 1.0) + rake (~> 13.0) matrix (0.4.2) method_source (1.0.0) mini_mime (1.1.5) @@ -164,6 +180,7 @@ DEPENDENCIES capybara draft_matchers grade_runner + http i18n pry puma (~> 5.0) From db1e18bb38bea8f5a817aeca7652018f94ab1764 Mon Sep 17 00:00:00 2001 From: Lamont Sampson <148111503+lsampson1974@users.noreply.github.com> Date: Mon, 5 Feb 2024 10:16:11 +0000 Subject: [PATCH 36/36] Refactored and updated the games codes. --- app.rb | 29 +++-- libraries/games.rb | 265 ++++++++++++++++++++++++--------------------- 2 files changed, 163 insertions(+), 131 deletions(-) diff --git a/app.rb b/app.rb index 6696b25..2f0bcec 100644 --- a/app.rb +++ b/app.rb @@ -323,12 +323,17 @@ if game_choice == "tic-tac-toe" - calc_tictactoe.render_game_board - - line_count = 0 game_display = calc_tictactoe.render_game_board + game_state_string = calc_tictactoe.get_game_state + + if game_state_string != "no_wins" + calc_tictactoe.print_message(20, 4, game_state_string) + end + + line_count = 0 + game_display.each do |display_line| calc_display.set_display(line_count, display_line) @@ -404,12 +409,22 @@ row = params.fetch("row") column = params.fetch("column") - if calc_tictactoe.check_spot(row, column) == "no" - calc_tictactoe.move(row, column, "X") - calc_tictactoe.computer_move + if calc_tictactoe.game_done == "no" + + calc_tictactoe.player_move(row.to_i, column.to_i) + calc_tictactoe.get_game_state + end - + + if calc_tictactoe.game_done == "no" + + calc_tictactoe.computer_move + calc_tictactoe.get_game_state + + end + + redirect("/games") end diff --git a/libraries/games.rb b/libraries/games.rb index 0bf163b..33fe0fd 100644 --- a/libraries/games.rb +++ b/libraries/games.rb @@ -10,6 +10,8 @@ def initialize @game_display_array = Array.new(@max_y) @game_done = "no" + @move_array = [0, 1, 2, 3, 4, 5, 6, 7, 8] + self.clear_game_grid end @@ -74,13 +76,19 @@ class Tic_tac_toe < Games def initialize - @spots = [["*","*","*"],["*","*","*"],["*","*","*"]] - @x_img = Array[" X X", " X ", " X X"] - @o_img = Array[" OO ", "O O", " OO "] - @game_board = Array[" 0000 | 1111 | 2222 ", - "------|------|------"] + @x_img = Array["X X "," X "] + @o_img = Array[" OO ","O O"] + @game_board = " E000 | E111 | E222 : M000 | M111 | M222 : E000 | E111 | E222 : ------|------|------ : E333 | E444 | E555 : M333 | M444 | M555 : E333 | E444 | E555 : ------|------|------: E666 | E777 | E888 : M666 | M777 | M888 : E666 | E777 | E888 " @draw_x_loc = 5 + @move_array = [0, 1, 2, 3, 4, 5, 6, 7, 8] + + @user_move = [] + @computer_move = [] + + @turn = "user" + @game_done = "no" + super end @@ -89,11 +97,15 @@ def initialize def reset_game - @spots = [ - ["*","*","*"], - ["*","*","*"], - ["*","*","*"] - ] + @move_array = [0, 1, 2, 3, 4, 5, 6, 7, 8] + + @user_move = [] + @computer_move = [] + + @game_board = " E000 | E111 | E222 : M000 | M111 | M222 : E000 | E111 | E222 :------|------|------ : E333 | E444 | E555 : M333 | M444 | M555 : E333 | E444 | E555 :------|------|------: E666 | E777 | E888 : M666 | M777 | M888 : E666 | E777 | E888 " + + + @turn = "user" @game_done = "no" @@ -101,187 +113,191 @@ def reset_game #------------------------------------------------------- - def render_game_board + def player_move(row, column) - row_counter = 0 - column_counter = 0 + move_num = row*3+column + + if move_available(move_num) + @user_move << move_num + @move_array.delete(move_num) + @turn = "computer" + end - line_counter = 0 + end - temp_string_array = Array.new(3) - temp_string_array[0] = @game_board[0] - temp_string_array[1] = @game_board[0] - temp_string_array[2] = @game_board[0] +#------------------------------------------------------- - while row_counter != 3 do - while column_counter != 3 do + def computer_move - string_to_find = column_counter.to_s*4 + if @turn == "computer" - if @spots[row_counter][column_counter] == "X" - for indx in 0..2 - temp_string_array[indx] = temp_string_array[indx].sub(string_to_find, @x_img[indx]) - end + random_number = @move_array.sample - elsif @spots[row_counter][column_counter] == "O" - for indx in 0..2 - temp_string_array[indx] = temp_string_array[indx].sub(string_to_find, @o_img[indx]) - end + random_row = random_number / 3 + random_column = random_number % 3 + + @move_array.delete(random_number) - else - for indx in 0..2 - temp_string_array[indx] = temp_string_array[indx].sub(string_to_find, " ") - end + @computer_move << random_number - end # Of condition block + @turn = "user" - column_counter += 1 + end - end # Of inner while ( column ) - - for indx in 0..2 - @game_display_array[line_counter] = " "*@draw_x_loc+temp_string_array[indx] - line_counter += 1 + end - end - - if row_counter < 2 - @game_display_array[line_counter] = " "*@draw_x_loc+@game_board[1] - line_counter += 1 - end - - column_counter = 0 - row_counter += 1 +#------------------------------------------------------- - temp_string_array[0] = @game_board[0] - temp_string_array[1] = @game_board[0] - temp_string_array[2] = @game_board[0] + def get_game_state - end # Of outer while ( row ) + state_message = "no_wins" - #self.print_message(25, 1, "Test message") + if is_draw == "yes" + state_message = "Draw" - #@game_display_array.each do |display_line| - # puts "--->#{display_line}<--" - #end + elsif is_win(@user_move) == "yes" + state_message = "You win" + elsif is_win(@computer_move) == "yes" + state_message = "Computer wins" - if self.is_draw() - self.print_message(25, 4, "DRAW GAME") - @game_done = "yes" + end + + state_message - elsif - self.winner_result("X") == "yes" - self.print_message(25, 4, "X WINS!!") - @game_done = "yes" + end # Of method. - elsif - self.winner_result("O") == "yes" - self.print_message(25, 4, "O WINS!!") - @game_done = "yes" +#------------------------------------------------------- - end + def is_win(move_array) + is_winner = "no" - @game_display_array - - end # Of method + winning_combos = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]] -#------------------------------------------------------- + winning_combos.each do |combo_number_array| - def winner_result(mark) + intersecting_array = move_array & combo_number_array + + if intersecting_array.length == 3 + is_winner = "yes" + @game_done = "yes" - is_winner = "no" + break + end - played_array = @spots.flatten - winning_combos = ["012","345","678","036","147","258","048","246"] + end # Of outer loop. - winning_combos.each do |three_indices| + is_winner - if is_winner == "no" - counter = 0 - three_indices.each_char do |index| + end # Of method. - - if played_array[index.to_i] != mark - break - else - counter += 1 - end # Of condition block - end # Of three_indices loop +#------------------------------------------------------- - if counter == 3 - is_winner = "yes" - end # Of winner check condition + def is_draw - end # Of winner condition + game_is_draw = "no" - end # Of winning_combos loop + if @move_array.length == 0 + game_is_draw = "yes" + @game_done = "yes" - is_winner - + end - end # Of method + end # Of method. #------------------------------------------------------- - def is_draw() + def move_available(move_number) - played_array = @spots.flatten + @move_array.include?(move_number) - not played_array.include?("*") + end # of method. - end +#------------------------------------------------------- + + def render_game_board + #Reset board to be re-drawn -#------------------------------------------------------- + @game_board = " E000 | E111 | E222 : M000 | M111 | M222 : E000 | E111 | E222 :------|------|------ : E333 | E444 | E555 : M333 | M444 | M555 : E333 | E444 | E555 :------|------|------: E666 | E777 | E888 : M666 | M777 | M888 : E666 | E777 | E888 " - def move(row, column, mark) - @spots[row.to_i][column.to_i] = mark - end + # Render user moves first : + #@user_move + #@computer_move + #@game_board -#------------------------------------------------------- + @user_move.each do |user_num| - def computer_move() + middle_repl_string = "M"+user_num.to_s*3 + edge_repl_string = "E"+user_num.to_s*3 + + @game_board = @game_board.gsub(middle_repl_string, @x_img[1]) + @game_board = @game_board.gsub(edge_repl_string, @x_img[0]) - rand_num = Random.new + end # Of render loop. - random_row = rand_num.rand(0..2) - random_column = rand_num.rand(0..2) + + # Now the computer moves - while self.check_spot(random_row, random_column) == "yes" && @game_done == "no" + @computer_move.each do |comp_num| - random_row = rand_num.rand(0..2) - random_column = rand_num.rand(0..2) - - end + middle_repl_string = "M"+comp_num.to_s*3 + edge_repl_string = "E"+comp_num.to_s*3 + + @game_board = @game_board.gsub(middle_repl_string, @o_img[1]) + @game_board = @game_board.gsub(edge_repl_string, @o_img[0]) - self.move(random_row, random_column, "O") - + end # Of render loop. - end + # Finally, clean up : -#------------------------------------------------------- + counter = 0 + while counter < 9 do - def check_spot(row, column) + middle_repl_string = "M"+counter.to_s*3 + edge_repl_string = "E"+counter.to_s*3 + + @game_board = @game_board.gsub(middle_repl_string, " ") + @game_board = @game_board.gsub(edge_repl_string, " ") - space_occupied = "yes" + counter += 1 + end # Of render loop. - if @spots[row.to_i][column.to_i] == "*" + @game_display_array = @game_board.split(":") - space_occupied = "no" + #---------------TEST ONLY ------------------- : + + #@game_display_array.each do |display_line| + # puts "--> #{display_line}" + #end # of test display + + #puts " " + #puts " " + #puts "Movement array ->>>> #{@move_array}" + + @game_display_array - end - space_occupied + end # Of method. + +#------------------------------------------------------- + + def game_done + + @game_done end +#------------------------------------------------------- + + + end # Of class #============================================================= @@ -448,6 +464,7 @@ def win_or_lose @game_done = "yes" self.print_message(10, 5, "Sorry,") self.print_message(10, 6, "You were HANGED!!") + self.print_message(0, 11, @picked_word.upcase) end if @correct_guess_counter == @picked_word.length