From 0014424a6d11c40fcb0f74292edcf39ef1aa53cb Mon Sep 17 00:00:00 2001 From: Teptao <1650163832@qq.com> Date: Thu, 25 Sep 2025 17:08:03 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E7=AE=80=E5=8C=96=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E5=88=A0=E9=99=A4InvalidInputException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Application.java | 29 +++++++++++------------------ src/InvalidInputException.java | 8 -------- 2 files changed, 11 insertions(+), 26 deletions(-) delete mode 100644 src/InvalidInputException.java diff --git a/src/Application.java b/src/Application.java index 0791925..4937bb9 100644 --- a/src/Application.java +++ b/src/Application.java @@ -39,7 +39,7 @@ public class Application { /** * 启动并运行应用程序的主循环。 */ - public void run() { + public void run() throws IOException { System.out.println("欢迎使用中小学数学卷子自动生成程序!"); while (true) { if (!sessionManager.isUserLoggedIn()) { @@ -62,7 +62,7 @@ public class Application { System.exit(0); } - String[] credentials = input.split("\\s+"); + String[] credentials = input.split(" "); if (credentials.length != 2) { System.out.println("输入格式错误,请输入正确的用户名、密码。"); return; @@ -80,14 +80,14 @@ public class Application { /** * 处理用户已登录状态下的逻辑。 */ - private void handleLoggedInState() { + private void handleLoggedInState() throws IOException { String currentLevelName = sessionManager.getCurrentLevelName(); System.out.printf( "当前选择为%s出题。请输入生成题目数量(%d-%d),或输入 '切换为XX',或输入 '-1' 退出登录:%n", currentLevelName, MIN_GENERATE_COUNT, MAX_GENERATE_COUNT); String input = scanner.nextLine().trim(); - try { + if ("-1".equals(input)) { handleLogout(); } else if (isSwitchCommand(input)) { @@ -97,13 +97,10 @@ public class Application { validateGenerateCount(count); handleGenerateProblems(count); } else { - throw new InvalidInputException( - String.format("请输入小学、初中和高中三个选项中的一个", - MIN_GENERATE_COUNT, MAX_GENERATE_COUNT)); + + } - } catch (InvalidInputException | IOException | NumberFormatException e) { - System.err.println("错误: " + e.getMessage()); - } + } private void handleLogout() { @@ -111,7 +108,7 @@ public class Application { sessionManager.endSession(); } - private void handleSwitchLevel(String input) throws InvalidInputException { + private void handleSwitchLevel(String input) { Matcher matcher = SWITCH_COMMAND_PATTERN.matcher(input); if (matcher.matches()) { String levelName = matcher.group(1); @@ -119,9 +116,6 @@ public class Application { if (level != null) { sessionManager.setCurrentGenerator(level); System.out.println("成功切换到 " + levelName + " 出题模式。"); - } else { - // 这部分代码理论上不会执行,因为正则表达式已经限制了级别名称 - throw new InvalidInputException("无效的切换目标级别。"); } } } @@ -156,14 +150,13 @@ public class Application { return str != null && str.matches("-?\\d+"); } - private void validateGenerateCount(int count) throws InvalidInputException { + private void validateGenerateCount(int count) { if (count < MIN_GENERATE_COUNT || count > MAX_GENERATE_COUNT) { - throw new InvalidInputException( - String.format("生成数量必须在 %d 到 %d 之间。", MIN_GENERATE_COUNT, MAX_GENERATE_COUNT)); + System.out.println("生成数量必须在10到30之间。"); } } - public static void main(String[] args) { + public static void main(String[] args) throws IOException { Application app = new Application(); app.run(); } diff --git a/src/InvalidInputException.java b/src/InvalidInputException.java deleted file mode 100644 index d98e57a..0000000 --- a/src/InvalidInputException.java +++ /dev/null @@ -1,8 +0,0 @@ -/** - * 自定义异常,用于表示用户输入无效。 - */ -public class InvalidInputException extends Exception { - public InvalidInputException(String message) { - super(message); - } -} \ No newline at end of file From cd7dc30e92d61ed3d60c4604f79a27139deedda0 Mon Sep 17 00:00:00 2001 From: Teptao <1650163832@qq.com> Date: Thu, 25 Sep 2025 17:18:42 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E5=88=A0=E9=99=A4IN=5FGENERATE=5FCOUNT,MAX?= =?UTF-8?q?=5FGENERATE=5FCOUNT=EF=BC=8C=E7=9B=B4=E6=8E=A5=E4=BD=BF?= =?UTF-8?q?=E7=94=A810=EF=BC=8C30?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Application.java | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Application.java b/src/Application.java index 4937bb9..eabd0a7 100644 --- a/src/Application.java +++ b/src/Application.java @@ -20,8 +20,6 @@ public class Application { // 用于解析“切换为XX”命令的正则表达式 private static final Pattern SWITCH_COMMAND_PATTERN = Pattern.compile("^切换为(小学|初中|高中)$"); - private static final int MIN_GENERATE_COUNT = 10; - private static final int MAX_GENERATE_COUNT = 30; public Application() { this.scanner = new Scanner(System.in, "UTF-8"); @@ -71,7 +69,7 @@ public class Application { Optional userOptional = authService.login(credentials[0], credentials[1]); if (userOptional.isPresent()) { sessionManager.startSession(userOptional.get()); - System.out.println("登录成功!欢迎您," + userOptional.get().getUsername() + "。"); + System.out.println("登录成功!欢迎您," + credentials[0] + "。"); } else { System.out.println("用户名或密码错误,请重试。"); } @@ -83,22 +81,21 @@ public class Application { private void handleLoggedInState() throws IOException { String currentLevelName = sessionManager.getCurrentLevelName(); System.out.printf( - "当前选择为%s出题。请输入生成题目数量(%d-%d),或输入 '切换为XX',或输入 '-1' 退出登录:%n", - currentLevelName, MIN_GENERATE_COUNT, MAX_GENERATE_COUNT); + "当前选择为%s出题。请输入生成题目数量(10-30),或输入 '切换为XX',或输入 '-1' 退出登录:%n", + currentLevelName); String input = scanner.nextLine().trim(); - if ("-1".equals(input)) { handleLogout(); } else if (isSwitchCommand(input)) { handleSwitchLevel(input); } else if (isNumeric(input)) { int count = Integer.parseInt(input); - validateGenerateCount(count); - handleGenerateProblems(count); + if(validateGenerateCount(count)) { + handleGenerateProblems(count); + } } else { - - + System.out.println("无效的选项,请重新输入"); } } @@ -150,10 +147,12 @@ public class Application { return str != null && str.matches("-?\\d+"); } - private void validateGenerateCount(int count) { - if (count < MIN_GENERATE_COUNT || count > MAX_GENERATE_COUNT) { + private boolean validateGenerateCount(int count) { + if (count < 10 || count > 30) { System.out.println("生成数量必须在10到30之间。"); + return false; } + return true; } public static void main(String[] args) throws IOException { From d32dddf0141e12ccb01492a1d33ae929a60524d2 Mon Sep 17 00:00:00 2001 From: Teptao <1650163832@qq.com> Date: Thu, 25 Sep 2025 17:28:40 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E5=88=A0=E9=99=A4InvalidInputException?= =?UTF-8?q?=E5=92=8C=E6=89=80=E6=9C=89=E7=9B=B8=E5=85=B3=E7=94=A8=E6=B3=95?= =?UTF-8?q?=20=E5=88=A0=E9=99=A4EducationLevel=E5=92=8C=E6=89=80=E6=9C=89?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=94=A8=E6=B3=95=EF=BC=8C=E4=B8=BA=E7=AE=80?= =?UTF-8?q?=E5=8C=96=E9=80=BB=E8=BE=91=EF=BC=8C=E6=94=B9=E4=B8=BA=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E4=BD=BF=E7=94=A8=E9=9A=BE=E5=BA=A6=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Application.class | Bin 7606 -> 7114 bytes .../InvalidInputException.class | Bin 355 -> 0 bytes src/Application.java | 5 +-- src/EducationLevel.java | 39 ------------------ src/InMemoryUserRepository.java | 18 ++++---- src/SessionManager.java | 17 ++++---- src/User.java | 6 +-- 7 files changed, 22 insertions(+), 63 deletions(-) delete mode 100644 out/production/TestPaperGenerationSystem/InvalidInputException.class delete mode 100644 src/EducationLevel.java diff --git a/out/production/TestPaperGenerationSystem/Application.class b/out/production/TestPaperGenerationSystem/Application.class index ed2fc01f0df8b71e6ff7b69e91e4735ef8ff2ed2..017762958393bbda9b8c532d6cf8c25474fdc102 100644 GIT binary patch delta 2758 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 HH6h^(Phir) diff --git a/out/production/TestPaperGenerationSystem/InvalidInputException.class b/out/production/TestPaperGenerationSystem/InvalidInputException.class deleted file mode 100644 index a9ea19301c3f9e13cc001fe8178f7bb9b0df3d39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 355 zcmZut!AiqG5PcJ4R%5lbQU!0`S_S(7l^!e#h2W*q`!-$TNV+M>rubW)1P^|IA61+! z1qHhc!@M{1-t6r6`tu9GJ=!q>>?wo|>?0zaz3P?j=h|ldhqu%$9T%1m-LYjiBy_sT zZ^OiuY_macs&F8sv0dq$=VQC9-5+f@D&~gJOxT*IdNDKQv!3O`w38y$`Baze@s@M+8&`?; Date: Thu, 25 Sep 2025 18:01:48 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Application.class | Bin 7114 -> 6798 bytes .../SessionManager.class | Bin 2793 -> 2762 bytes src/Application.java | 31 ++++++++---------- src/AuthService.java | 2 +- src/SessionManager.java | 13 +++----- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/out/production/TestPaperGenerationSystem/Application.class b/out/production/TestPaperGenerationSystem/Application.class index 017762958393bbda9b8c532d6cf8c25474fdc102..e24d313dc02355eb1926b742c275b31a4bdc8daf 100644 GIT binary patch delta 2598 zcmZ8j4Rn*$8GhdUeP5E>v`L#nS_&zYQktY`Em$Z}ph&S8Q0NefRR|@ggte)r37c|Q zj?6QiN8I2}v<`4OT(=3^_*tO!XRtY#Y;$gI?nn3Meq}$5&HZVWz4!Y<4`-)6_ulW` z`@KKU^Stku3oQ@NbzOLW>;(YrwE39pfWzL@7-?>l&p6ukHtZ327@v^ywUs4%36@Bc z3*C?cpTZ+jYBT3QD)1N_1hFli+S;Fp4fYLYGcNe?xWK2enNXY@>iSSJ)4Ofi;J^Ui zQD+AQ4#~?}Me}C_o>Z5d$)VNRfkZml>%wPoSi{o-pTh{jyFI=m9_^2(`l6kwOrkH5 zmb3I(H+@0ii+G0M-x2RmZjEOWD-x+hn&)MM*;IyLtLvP-QF%Hl@FgS&~WsQw=}#Ya6z7R*6HW*9f9xSWqH{-U2niE0^diw zywg>#`(VLt9Y2(ZU19fY__2nc2>cX3ldrp$x!=IgHT**0m-v;O?XLE}DezIe?1K$& zsyKcp@O%70ZgMxe-@-)=e-ijJ{vscDcT`_eZ~l$oF_6nAzem?3~^NBshJwz+y z#gZE8l*Qg4-6R{mwX{mE_qNf^a=$m~Uc)k=h9K$GC13Hjd)B$=R$8yo2F{AQWzhGk zt%opE#(Xoa8r>nMl{S-Ic9qWXGP7I_f=Rc-0iwxrq%_tU;JvBPc$~~M1W<-5OyQkb z2%;I&(TW*V!KdZSE3kknX$sF%Fpa8cD%&E304!{6VOi4(Wlhlu%!ZB-ufuG!!LXn_ z13}XQP2;r<7QKXm#)_z#J#-c#J6ZNnPT6WhF^?^5YaU8CmMK_(8Z1N|79)x!n9KAn zLOb7Eju<-7g%yb7Mx?P4_aJ8YtvBM?S%|y@AEX&n!?8s9d?wYh*BGKSi|Syd+3Zcl z$vZjTs^={gs2{d*)M@A*hhL-6IGQyKX~vsI?tJB4j$Gxvz5XPc^SD2D94)>FZO_Bf zZ4Gth@z8ocD9dAQ9vfEqJ{itq-!NSDdF&s-yn22d9)?@Z2S!k*=G+s*m>fQhr`qbP z^7#BPbTuCtfm>PravqD0u{$d%m|EfCaV^8t#cD(}?!?rxWy*hFZlazx<9^YetB4hXgJI!5-k}2~6 zPAbK+8f3S3GFo?`n&lEfb^-}MCR3D?R!B4y0#PedHacqYA~kXfN*Ow691#uYIXG^~ zst^ErjNjGy^k~k^`PeGO*{dc7!SE=4WWj0`C z`lA)CcI)*HzawBD#a{_ep~>&CZ4TJ|j!|5;;0)f*<6mR=FN;BALjjGQ9Y?MukMa8) zG;-x76~X&gBVa4swZMDfJlV#G>z|JlGd6>ncCI$y!<@w3yt)UK*vXZ=i>vS>TyZ%T z)4eRK-Nd8K8g51_UB?=8C~PK>J!YU5$o7^D6=3m%J}g}?h0d19eF75{%RA7mB}v7;wU2RVKR+*p=y zpH;=?2PxtCW1Fsq6%vQ|8IY!Gx-ufm_CV7P^6!^Bjgo lAK)7u#(1MKt~AD&F;=ZMrdy10Ep6miTzvgDx}7#5@IPmw)L#Gq delta 2922 zcmZWr3sh9s72Ri;nfGSq0mHz61EQ#ad_|&wqGA9Mu>)A~M>K&E21H>-hZ$Xs?V6^h zD@~&L-K3RhjixrVO|%h{5lCawHZ_&BY18zR{?lLjv%h?rYKivT_ofu>TC?7}@4kD_ z-e;eE?wk86CaUZcSI5r-sG~h+>_@GZyzbJxZt5o` zLw#L#9Kshhd~ z^;r!uoD+|#Ip#49IA-{;k$TEykeVM_By_=;0GFhh#wJ>8oDE0 zzA(r2`uF<#35h+S;DA1E@eMHjTtP}|YoYi0b*$zB{8+|EaF*5sht!JwXmvW6PFw} zsc(`)<1L9IUn^UjtdUdhP3rZB+rq(+uh+lM7vAB5mGh%if~9ojw(erK7rD6z=u{~~ z+^v--XKIus3z`s$1XRiv7qxu#C7P{K4$TqoYs*)=nwwfW8XH;~*4J)m=%{bq*s_5@ zO^2ATkO=3LpTw^7Z>5`TsIJ=B0O)Iah zUzXh{wM8HEvKtFW@OZ^>TgKU^lWK{!h_{n-=@yaU%%N>!i8G&W6CKVP>J-PEWsdCx zGcCv=mAb_n&bp)?JN42Ih5DqhJ4Hdt>og!HQ;N(%Vw%@dW{EW}7b#+^YhF2fn#pI< zT$%@>TppV!kDv3WJ*&WMF3DiHU(yiJ8NVJLDZdnF5Ln2njp!Ft&NQx8UEtQsWqbt%WHh7-#fcLj5*K>>TK40WhLJ@({mnx`|QN1XmDq4aBTFPjWC(lHAs+y-HQ8&z! zC{WNo3AaMaCb3AtprY^8a|bAynajNQ6+MGRG2G=HL6z$s>+>+RClt4}o1OMi9Bga1 zIA_Uw3=eJQg=sOYk6}x*>(eDM93FzbD2AiMs3_vc=wm~0$id^o$dmWa55ZkBiZ9d@ zWykQ8ynJ~W4hb_7!-_MEoj_8vI#vqUz?yAj?KdNj?}gZc#khsF+RAEe^L72PIA&l^bwA3;a!y@c%e9kuQ#)B7l%+-Vvga}meNstuiES}U%(6rrSYQ z(_=Dm$En;6FHjUZYTBkP@38oqXsCsRrNF9i-m_5|=`NsN-lDP>AJ^ECh6&ROhd zCw`PQ`4~#LoJ;U=?%F%pdk5HscOrsM@|(N(=>YD=J$MNB^8bf}IE6!o|JHMe2$HCd zrB&EB)l^UO*hehRl(eUHck*WlPtYoAU@5a8Xf-vmjI|h`HPpn#@M1fyr4R8JN;bGW z%8XTBUS+&%=6A9v*)UyWC`CckO$zoacuT=M3NEu{uVCqQo<6~iW4LZ5N0i4Sccbn) z_S{qaXc(A{&*KMlw-~3WV~V~b?hKRsI}{JrW(12Ot@r{`ic`rIqqHF?=3$rWZ z7=s+229Ow~5A)$H+r&ca`J+SAv{$KZ>O7gN%gf*MRGK+Tv(DlL8J=`28XBduVjFbG qjkJmHB~VC8v01;i>({ON^;Z4bp8 z@809Pe*hT4$KU#X>xsrYCzrA-*;FoDm`|Oy%8P~hJ|8@23ZNM+0+EVooiGb#IcpWm zBde3@nAVcfT};?V_uFVhD;C z$1tkncmO9bwv+8@#WM4xSX{P9q1xzTF*QR0Ey`$S^L=5;JRZOVChdqanwZ8Z9Ww#E z>d5LezB52TFUjy+!Tw5F66frHl|Ox6mMJ-U+JC8g?MLc!(T0&?(W+SGY-!507K(Ef z5Ayb~))p%IP{Ji0Wm&Xh=e57ZiaqQ$#7B0{-7Qr6M|aa1mmC$D`QU;EHw0cI>gFkU zYQ_e{FEm^@U2_6LP|<)h#DS_4&e8(BcpY!Z1h%G+4@m!JCIt5K-UL6_es%cnfbkDZbX**JO$i6yD?HW+2Fc%d(B6Bi~fZO6wh_mWcMy`d)~!CONe?k;7aQ;1){DQERNy^m?>kJ=p0+N@L}~+MwmAoD&axE^ zF8`3Eki~f?>{CzU+*VlcwlJ+;;{xWSFT+zjtAgJ~>rFnW3SO-_uxqeMDW%vCJqH}6 z!qgAkOci5PWE>GreM_xqU9BiCa^k`nfC3R>DgL!(DnJZSZjEU+joav$G7@*tk(hR6 z)Z{vh>wG@JOM!1tQcT1D*%6-mu@(uPr7@Tcr`OT-J)T!G>NT__!x;z0R0;Pa!#xgk zYZ*1B{>%V=j#m$7qOG(IUOmR|=$+lbD;(N2q>1{81|9S)(GbyygQB-^G;tSeCxLZL z83##MPFZobwaeMcY4&r9Q=Y*m?C^8G`I1t6$6dWb34X#Xu5#&aaqTv^K2oq}oR!tKRv=l^LUBCo2G>gmbVfV^%FWtS1Kl;)% zeW(wOU;3a%924ya1SZ1GY>S<{U1PwFi=w?z9DpC5eE5x+{1yCDC9bOWsPUdY}n$F3bT3VS< zBfaX;pkY}U%dtYB-1}IYmd-&rrsuOxLQcu7K(w_j(VNOAb%*=A@7xUyBl2Un*T&-@0(A7ulLH)?yv0`@{+W0`-abaoZZr%8A0uE)6dWG|wv*&t_#> z&mOST`3Z*Adod{|6}uod2&{f_{n6~qjk(*O&duC>{@}COD|enhn3?-#=C=<&3Sm7q zstjxrSk{`DM;vr)!%TN6cCBdB5DTLnuaID=v@P2N8e0Z07)~LO5fHXgzj zbZFQb#x`tc;ugASmYp(8ox(EBaSg9g!d^zpICT5c!q7wLR8{l3KvSQQN@e9>GGkfU z#cn&5+a6*aG18g;a@wt&_6e+;58Rh>(9s=P&@qHJv0uZ1FblV*q*gth1hgqVo0kJ) z0-K6u^h&v_ZLzXZc0q3#hj3V6#e_aCdn}VBb=q(;oT*ZFatpxz&BWX9xKIusZAKB?9We(N_$9W zp|QjhR#MNN(rrW8{>ySFV~|oc8zNrlHPsBICDA1ip?b-2)`PoJ!!WCOUg4pPZC&v8 z2{TUH@z)DfwR)Y{c8c8cZf}O9nJRp*F>j((osJdS`D^oXxJMv)WsIDtsR1kQJRwqZnu_AUK;(OQagzp4IP>xy* z(hhr07;+)2a1y6{fXjqa8@Anr_6*I@;PA1Z-D%_@g2VR_`2kw&=}iO^v8U~i`DL2! z)mX#x8hkdmV;R(@tH=si!QYkiXe4XiLukTAUMZ*fr51s|uv$aeK@D&JNp1pXaMtH> z)aOwXYyS!SxrgXItelUihLQlA8G0Mzin&oOcbV7tQ2{l0hnp%v&J_gOM;|3nbxbH+ z{xmHF-Ad4H)OCB2RMkGHz`JG}Lg7tw;>qaY>@LEoD3BRNa*4%F3m5NOa&d~;@OC~&$|~s% z?a#nGuOE&!-$%=1rMfG*7f_Tb0^7G7hbe8G|CJndaXr}^3bHpqVvNWt%m73Up;h9& zt)BQ>joig%!oRxZ7QOg)h>r?hWwnVnEed6%5XwkV zC>knSB9TZPX{M3!!@0mw(T*`^O;51<8Y-jlY0ucHjAOphsf@nq=zz+NM{F%L&XcUP z6iZmLQ^qJ%nnW`!?DIuAiYY|(ISX=T@tHuLR+JvC98nj< K6fWX28vg-aQH4YR diff --git a/src/Application.java b/src/Application.java index fa307fb..8a36ada 100644 --- a/src/Application.java +++ b/src/Application.java @@ -79,10 +79,10 @@ public class Application { * 处理用户已登录状态下的逻辑。 */ private void handleLoggedInState() throws IOException { - String currentLevelName = sessionManager.getCurrentLevelName(); + String currentLevel = sessionManager.getCurrentLevelName(); System.out.printf( "当前选择为%s出题。请输入生成题目数量(10-30),或输入 '切换为XX',或输入 '-1' 退出登录:%n", - currentLevelName); + currentLevel); String input = scanner.nextLine().trim(); if ("-1".equals(input)) { @@ -90,10 +90,7 @@ public class Application { } else if (isSwitchCommand(input)) { handleSwitchLevel(input); } else if (isNumeric(input)) { - int count = Integer.parseInt(input); - if(validateGenerateCount(count)) { - handleGenerateProblems(count); - } + handleGenerateProblems(input); } else { System.out.println("无效的选项,请重新输入"); } @@ -116,7 +113,8 @@ public class Application { } } - private void handleGenerateProblems(int count) throws IOException { + private void handleGenerateProblems(String input) throws IOException { + int count = Integer.parseInt(input); User currentUser = sessionManager.getCurrentUser(); System.out.println("正在加载历史题目,请稍候..."); Set history = fileService.loadAllProblemHistory(currentUser); @@ -125,11 +123,10 @@ public class Application { System.out.println("正在生成 " + count + " 道不重复的新题目..."); IProblemGenerator generator = sessionManager.getCurrentGenerator(); List newProblems = generator.generate(count, history); - //命令行显示生成题目 + // 命令行显示生成题目 for (int i = 0; i < newProblems.size(); i++) { String problemLine = (i + 1) + ". " + newProblems.get(i).toString(); System.out.println(problemLine); - // 满足题目之间空一行的格式要求 System.out.println(); } @@ -143,15 +140,15 @@ public class Application { } private boolean isNumeric(String str) { - return str != null && str.matches("-?\\d+"); - } - - private boolean validateGenerateCount(int count) { - if (count < 10 || count > 30) { - System.out.println("生成数量必须在10到30之间。"); - return false; + if (str != null && str.matches("\\d+")){ + int count = Integer.parseInt(str); + if (count < 10 || count > 30) { + System.out.println("生成数量必须在10到30之间。"); + return false; + } + return true; } - return true; + return false; } public static void main(String[] args) throws IOException { diff --git a/src/AuthService.java b/src/AuthService.java index 9e358a2..7058d98 100644 --- a/src/AuthService.java +++ b/src/AuthService.java @@ -17,7 +17,7 @@ public class AuthService { * * @param username 用户名 * @param password 密码 - * @return 如果认证成功,返回对应的 User 对象;否则返回一个空的 Optional + * @return 如果认证成功,返回ture,否则返回false */ public Optional login(String username, String password) { Optional userOptional = userRepository.findByUsername(username); diff --git a/src/SessionManager.java b/src/SessionManager.java index cf490c7..25c25e5 100644 --- a/src/SessionManager.java +++ b/src/SessionManager.java @@ -9,6 +9,7 @@ public final class SessionManager { private User currentUser; private IProblemGenerator currentGenerator; + private String currentLevel; private SessionManager() { // 私有构造函数,防止外部实例化 @@ -74,6 +75,8 @@ public final class SessionManager { } private void setGeneratorByLevel(String level) { + String tempLevel = this.currentLevel; + this.currentLevel = level; switch (level) { case "小学": this.currentGenerator = new ElementaryProblemGenerator(); @@ -86,6 +89,7 @@ public final class SessionManager { break; default: System.out.println("错误的难度等级: " + level); + this.currentLevel = tempLevel; } } @@ -95,13 +99,6 @@ public final class SessionManager { * @return 中文级别名称,如 "小学" */ public String getCurrentLevelName() { - if (currentGenerator instanceof HighSchoolProblemGenerator) { - return "高中"; - } else if (currentGenerator instanceof MiddleSchoolProblemGenerator) { - return "初中"; - }else if (currentGenerator instanceof ElementaryProblemGenerator) { - return "小学"; - } - return "未知"; + return currentLevel; } } \ No newline at end of file From 5a04f6b01399b6b21d786129396c171fb961de56 Mon Sep 17 00:00:00 2001 From: Teptao <1650163832@qq.com> Date: Thu, 25 Sep 2025 18:15:07 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Application.class | Bin 6798 -> 6696 bytes .../EducationLevel.class | Bin 1603 -> 0 bytes .../InMemoryUserRepository.class | Bin 1540 -> 1474 bytes .../SessionManager$1.class | Bin 681 -> 0 bytes .../TestPaperGenerationSystem/User.class | Bin 1796 -> 1758 bytes src/AbstractSessionManager.java | 66 ++++++++++++++++++ src/AbstractUser.java | 61 ++++++++++++++++ src/Application.java | 17 ++--- src/SessionManager.java | 2 +- src/User.java | 42 ++--------- 10 files changed, 141 insertions(+), 47 deletions(-) delete mode 100644 out/production/TestPaperGenerationSystem/EducationLevel.class delete mode 100644 out/production/TestPaperGenerationSystem/SessionManager$1.class create mode 100644 src/AbstractSessionManager.java create mode 100644 src/AbstractUser.java diff --git a/out/production/TestPaperGenerationSystem/Application.class b/out/production/TestPaperGenerationSystem/Application.class index e24d313dc02355eb1926b742c275b31a4bdc8daf..2aeebf8218acf32ae39bb3f433fd528dae4cc086 100644 GIT binary patch delta 2196 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 G{(k}V%%xKR diff --git a/out/production/TestPaperGenerationSystem/EducationLevel.class b/out/production/TestPaperGenerationSystem/EducationLevel.class deleted file mode 100644 index 248f8098236af8b9076ddc11ceceb5fabde36f33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1603 zcmZux&vVmO5dNMeS+bCWk-;Hp0wE2p?G#cV^al=ULSl$pJ4xf#)3hhW5ka8H;K(^M zOb@;F+8%o8p*=9nq@fKN7#Pm{9dO`3-~`=$7GMW7BR}nXyWj5j?OQ*2dH)fB3s}+- z6X+?fw(3skHG;Cc>G}x>s1`KD1@y(GQe}E+Ss+#J_A0QOVIje8@k(iSwp`?`eHJX< zQs+vS=6IvW!hWO(YNR$@{=QfhIPlY6EE6`;I#L!6;*fw=_ZxvLa4?%IUv)N}G2aQ+ z#uiqty7jPNq8EpC^jYY~2L%7tp%}E*DbJ?kx7>xx0%x-w(KEiYu~F#QsD@21SSxg9 zU;v3fXyFKs60Zp_@WM%fOea(nS<2Oz-!Tir_)s9>vv~8)Iu&leo5v*A;}$-`#{?@& z+z?1-bMMhYAZHT$$WnM zH!>OWD+^Q1T_1T(UY%*Il2-f6Uf|BR)>qu-cg~7WJ0tJOn%jG2SmZ|C@oP@g& zzgBUsN6Czdx*uH-CCh=s9oq0^n%GF%jI$=#beMSAtpfNE2H zJca23WC!L4N6(qc?^U)j{(?ztd!o(JDFR z|HaVW!ZR{MyKpVakigeOy&Zgu;4}gu-XrDFN9UEv!GS+9I68RxoZ6@EAe-O8C%+@! zr*8eMh`(PwmC`6unv9GbLK??#lxiNv5VAP_hEtlF^9^xgHS&@ZP^NFv;3X0|Y#|Q6 zfR-|OGTxA3Z=g5+5Mo)`hEiQtx1m>;wQagNOs~6-1}d13f`5<&0pkxS);_J+XYS$b zT`1E0Lbbn?rY_BbW=}}d+{NTwB)LUxWLp*-r{Z;Lt3iJ+8i~|aegTW*7sI#z127yo AX8-^I diff --git a/out/production/TestPaperGenerationSystem/InMemoryUserRepository.class b/out/production/TestPaperGenerationSystem/InMemoryUserRepository.class index e8cd1e92c68fe2933649ac6a118bf2911b275926..e398e3fcbd01600a8e689955d4df36ff200c9e80 100644 GIT binary patch delta 680 zcmZXSOHb5b6o#L#T&A{FoCXI51VQ9732)Ibht&6_gc+mZYx6hAD?sCw<(i5 zfk>OQi8$R@%df8|O*;J1D;v4&wn=9I#L^WAv2=?#TYHx~_$ZdUV)^ssleVM+AeMW9 zNZVKBh3-2%pwAmKlJ-L$g?Q{Rz!PuDm{mhxPmDzsA4JJQ*Qk>7uxxC|&W7|AR7xEM zHBLx6IQQnu8!~R>8@2n?moeYDhvhbZ$9?5CyVd`L77bcTL8}I>0@{m5#WaYOg1828 zA7qLx2~840dWu0(gJda4YmhDiyL#_2sVN+(S1HGqM6T08SWwL z%5UoUOFd7;;uIp{8RMc9&v_v+N_;{MIUwxE72l`V;3saD{vEk!;6K$*8u@MfL6O4E VmxIK{1e3xG-)72^c3K-}E&ywmh5G;i delta 760 zcmZvaOKTHh6o#K~j7`jZ_A<7ywYKrn+NRN(iyCXawM|S$6B|=66m%ilg&?}|vdqSf z2!#;AMG@S)@dmb4LeNTr!|5|UTbiiMD%y*UY&?uZpJqM%ip+5B z=Row|j@WsdZEO#+L$i~CdP2=qcgf7vw@+3U@25fx`$am$h!kHR&#x{lB)zS6Yxa06 zwUpd!wwMdC*XN>4`h_UdQhb|#u(JHnDEDg)c*;P*%@;x(^r`5&4*6BuTkf#t2uJI- zm9&pD5oA&`MYf)|rqzj;kF1L-o zYql;CUB`uySA?CxH#oD-pwsyu88T$335gjJ^GLjL+NdF;O-RC!YN82B8Ib4L>Loh4OBXdFJf)kD^zcRguJ816N+f#C zD~gn)Qk-U5{1hL_Nwy?+c(%ot7`J$jv&gY$^3cM2t7kbx&7jCy^PfQ?qs$pL{ryT6 KX`L~`v%dkKIG8j5 diff --git a/out/production/TestPaperGenerationSystem/SessionManager$1.class b/out/production/TestPaperGenerationSystem/SessionManager$1.class deleted file mode 100644 index fee6f24c47a8d60c3d25cd81daab0684b1078240..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 681 zcmZ8e+iuf95Ix(tc4FMtZ3<1xtw1OVAS#d$4|3J06fQC7jvjNusqDeW?1Zv%7hnEt58fu z%3x17XzgCC1Lr__imJ{DQ~KErxD{wRxN67di1*<^;f zqo6_RiyoHXGdQmfg6P@7TdMQFj%jkmLldhMrn8Y$oLZ}Ox`BfW3>(LM%C}Rl#@hoO zm&s&LigeV=GMyQLmWOpCU`N63ZrC%_MGuz@W%Yv>eFs-a^Q^}H@K_`TL;XpTN+pY@ zmDC|c@92?WSPG>QgYx}QWUu)!C1xem2~Q7sCJjC%7vh2^@95#D*o}3WC1OvSjOOfD z-81S`xu=p;=TeO$QB3s6L6=4{8%li*L|*iDPAz(YQX<<)d7g{h-=uL|rm-@=Wd>qA zVy@`B4P$Lg`^aJeVm-`LQSF;wrW7*pO4C`eD*9gv^!3~0T1;0>w1FKlWd9-i? zTV!wH0UnaA;W`zztMU=ufj${%(_V)C#-WJl-vJ9ZtAH&^2cZs~w=1TDJ7nFeZ*u(l EUorHLYybcN diff --git a/out/production/TestPaperGenerationSystem/User.class b/out/production/TestPaperGenerationSystem/User.class index 5dc04d7fb2bc2cf632544e35f56aa9e96f25bb9a..3124bc254627c364331b5d5cf5d8060e3bc4e1b8 100644 GIT binary patch delta 675 zcmZuuNiRcD6#j1CRIj%hW3{wJ)zIP@Yo2E+@dIpL(qbWzP?kg@v5`n~?XB!AND#3= zVrOe%=O5TxiE~RrW+$^= zOr=teGL+|TXTlX60Z@x)E4#62uV$9)?3xJ|DmkhU5+N4#L{M#@hNBiyvA~j^80rl) za5SPx9I+(p6HlyOys{$k!4AcVYd1W?P|#|n?W}Dv%co<^Br+2QCgs{G(WbnpvkWn@ zti%)p^TJZ+{G4bNOD^OMFldOAO^9PP>Ma4T;lHGc3(ev|jrdw9jzc9IMk_4wu7>tF z6hgG2UE-)>k!R$!_!W!`3J6SA&wunoj^N)7as*`z9gbk{e{iJ}*p1F_w8&}Y>EBHe zr)G3HZu0-%6mkXT=9ofOofe$bw_B!@*1ScUJArQjh&`?oOSlCFBENC1gs(^$L ztu+-tAXF}b1Q9|4QGrBDABlz<{s7_|dnHWdV&1&B^BwQK-H$wvI^X_$_yk}Tw>!?W zazemuG#}KrTJ2i%akC{bR$FUq-LJPdA3f}SS&kEZ*hLbl&d$1;bTQTWH6A|VB8`l8 zM1C}fqc)DY$m6(P6xGog%-SfpD8kcEL{%*4T`?2=UseAUFB9=X@t~P*g`Q?E3mmHW zje5K83qKad6$e+bX5*UaVqH7(ySSe4v;4X$oG1Z`Jrt7nZWu5 zy(CqNUg!iDw6v?3O-bWP^R#b3A*A?mlgas^8 zJk8xKaVsI5Bg%rbqh`ouoDZCrxNI|YOnpS?t~3^R-s6PP9~^&vV1QWQB5}c>a=3^~ VOh%})%Cmy&tQ=-Ha0?rl{0pB8W1|27 diff --git a/src/AbstractSessionManager.java b/src/AbstractSessionManager.java new file mode 100644 index 0000000..e5fb5be --- /dev/null +++ b/src/AbstractSessionManager.java @@ -0,0 +1,66 @@ +/** + * 抽象会话管理器。 + * 定义了会话管理器的基本框架,包含核心的属性和必须实现的功能。 + * 子类需要提供具体的实现,例如单例模式的实现和题目生成器的实例化逻辑。 + */ +public abstract class AbstractSessionManager { + + protected User currentUser; + protected IProblemGenerator currentGenerator; + protected String currentLevel; + + /** + * 在用户成功登录后启动一个会话。 + * + * @param user 登录成功的用户对象 + */ + public abstract void startSession(User user); + + /** + * 结束当前会话(用户退出登录)。 + */ + public abstract void endSession(); + + /** + * 根据用户的选择,动态更改当前的题目生成策略。 + * + * @param level 新的教育级别 + */ + public abstract void setCurrentGenerator(String level); + + /** + * 检查用户是否已登录。 + * + * @return 如果用户已登录,则返回 true,否则返回 false + */ + public boolean isUserLoggedIn() { + return currentUser != null; + } + + /** + * 获取当前登录的用户。 + * + * @return 当前用户对象 + */ + public User getCurrentUser() { + return currentUser; + } + + /** + * 获取当前的题目生成器。 + * + * @return 当前题目生成器实例 + */ + public IProblemGenerator getCurrentGenerator() { + return currentGenerator; + } + + /** + * 获取当前选定级别的中文名称。 + * + * @return 中文级别名称,如 "小学" + */ + public String getCurrentLevelName() { + return currentLevel; + } +} \ No newline at end of file diff --git a/src/AbstractUser.java b/src/AbstractUser.java new file mode 100644 index 0000000..8e630c9 --- /dev/null +++ b/src/AbstractUser.java @@ -0,0 +1,61 @@ +import java.util.Objects; + +/** + * 抽象用户类。 + * 封装了所有用户类型共有的核心属性和行为,例如用户名和密码。 + */ +public abstract class AbstractUser { + + protected final String username; + protected final String password; // 注意:在生产系统中应存储哈希值 + + /** + * 构造一个抽象用户。 + * + * @param username 用户名 + * @param password 密码 + */ + public AbstractUser(String username, String password) { + this.username = username; + this.password = password; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + /** + * 比较此用户与指定对象是否相等。 + * 如果两个用户的用户名相同,则认为他们相等。 + * + * @param o 要与之比较的对象 + * @return 如果对象是同一个用户,则返回 true;否则返回 false + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + // 使用 getClass() != o.getClass() 来确保子类之间不会错误地相等 + if (o == null || getClass() != o.getClass()) { + return false; + } + AbstractUser that = (AbstractUser) o; + return username.equals(that.username); + } + + /** + * 返回用户的哈希码。 + * 哈希码是根据用户名生成的。 + * + * @return 此对象的哈希码值 + */ + @Override + public int hashCode() { + return Objects.hash(username); + } +} \ No newline at end of file diff --git a/src/Application.java b/src/Application.java index 8a36ada..b623d86 100644 --- a/src/Application.java +++ b/src/Application.java @@ -24,7 +24,6 @@ public class Application { public Application() { this.scanner = new Scanner(System.in, "UTF-8"); - // --- 依赖注入与组件装配 --- // 创建数据访问层的实例 UserRepository userRepository = new InMemoryUserRepository(); this.fileService = new TextFilePersistence(); @@ -114,7 +113,13 @@ public class Application { } private void handleGenerateProblems(String input) throws IOException { + int count = Integer.parseInt(input); + if (count < 10 || count > 30) { + System.out.println("生成数量必须在10到30之间。"); + return; + } + User currentUser = sessionManager.getCurrentUser(); System.out.println("正在加载历史题目,请稍候..."); Set history = fileService.loadAllProblemHistory(currentUser); @@ -140,15 +145,7 @@ public class Application { } private boolean isNumeric(String str) { - if (str != null && str.matches("\\d+")){ - int count = Integer.parseInt(str); - if (count < 10 || count > 30) { - System.out.println("生成数量必须在10到30之间。"); - return false; - } - return true; - } - return false; + return str != null && str.matches("\\d+"); } public static void main(String[] args) throws IOException { diff --git a/src/SessionManager.java b/src/SessionManager.java index 25c25e5..292b2b0 100644 --- a/src/SessionManager.java +++ b/src/SessionManager.java @@ -2,7 +2,7 @@ * 会话管理器(单例模式)。 * 管理应用程序的运行时状态,包括当前登录的用户和选择的题目生成策略。 */ -public final class SessionManager { +public final class SessionManager extends AbstractSessionManager { // 懒汉式单例模式,确保线程安全 private static volatile SessionManager instance; diff --git a/src/User.java b/src/User.java index 7a1ecb3..74fa5ec 100644 --- a/src/User.java +++ b/src/User.java @@ -1,30 +1,15 @@ -import java.util.Objects; +// 修改后的 User.java +public class User extends AbstractUser { -/** - * 用户实体类。 - * 这是一个简单的POJO,用于封装用户的静态、持久化信息。 - */ -public class User { - - private final String username; - private final String password; // 注意:在生产系统中应存储哈希值 private final String defaultLevel; private final String storagePath; public User(String username, String password, String defaultLevel) { - this.username = username; - this.password = password; + // 调用父类的构造函数来初始化 username 和 password + super(username, password); this.defaultLevel = defaultLevel; // 根据用户名生成唯一的存储路径 - this.storagePath = "./data/" + username + "/"; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; + this.storagePath = "./data/" + this.username + "/"; } public String getDefaultLevel() { @@ -35,20 +20,5 @@ public class User { return storagePath; } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - User user = (User) o; - return username.equals(user.username); - } - - @Override - public int hashCode() { - return Objects.hash(username); - } + // equals() 和 hashCode() 方法已由父类 AbstractUser 提供 } \ No newline at end of file From 115d4b0ee153b1d2b222bfa047c5c02cf6c29b93 Mon Sep 17 00:00:00 2001 From: Teptao <1650163832@qq.com> Date: Thu, 25 Sep 2025 18:28:15 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E4=B8=BA=E5=85=B7=E4=BD=93=E7=B1=BB?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E6=8E=A5=E5=8F=A3=EF=BC=8C=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=92=8C=E5=AF=B9=E5=BA=94=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E7=B1=BB=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Application.class | Bin 6696 -> 6663 bytes .../AuthService.class | Bin 1185 -> 1208 bytes .../InMemoryUserRepository.class | Bin 1474 -> 0 bytes .../SessionManager.class | Bin 2762 -> 2790 bytes .../TestPaperGenerationSystem/User.class | Bin 1758 -> 1144 bytes .../UserRepository.class | Bin 248 -> 1451 bytes src/AbstractUser.java | 2 +- src/Application.java | 2 +- src/AuthService.java | 6 +-- src/IAuthService.java | 17 ++++++++ src/IUserRepository.java | 16 ++++++++ src/InMemoryUserRepository.java | 33 ---------------- src/UserRepository.java | 37 +++++++++++++----- 13 files changed, 65 insertions(+), 48 deletions(-) delete mode 100644 out/production/TestPaperGenerationSystem/InMemoryUserRepository.class create mode 100644 src/IAuthService.java create mode 100644 src/IUserRepository.java delete mode 100644 src/InMemoryUserRepository.java diff --git a/out/production/TestPaperGenerationSystem/Application.class b/out/production/TestPaperGenerationSystem/Application.class index 2aeebf8218acf32ae39bb3f433fd528dae4cc086..6c60d237acbf2e5ce50a8ccd6c1b4ae69a04fd44 100644 GIT binary patch delta 1057 zcmX|=TWnNS6o$Vwb7sz54y7~9)DDi)6492SokGjh4i-xkq%zS+Z4|7ggA_8gv;n7} zqSgzR1R*iqJ_t`r)be1AsF~P4nW!Y?#VBYIFBH6>XuaTF!Mdi6zU;I2zt;b+wf?=& zp@!WJugn%HG3Bzuid1DGtuyIp<##JkAF;A3BV4!c+#X3!da-n@=1* zR`%>kV+8Umbp< zUBP@`TYg)vcXJpIe-u0U)9ek_`u}!Vf!D`H^Hy+)?>JMAAYv{Cla|{N%hWk@L$=`V z*q8{gPW%pU(rE^r6Yh|D&^c>^Cln{nWn9HP>Zv5nd~+RXh(R<+udc^fs{ zP6O+>hV{z1Ls=c%%3Zo<&Fbi&ed{If%g>9b4ASv$6TZ>#bVY7 z9|@zJ0*xvXALaD)eujA_?TLBf#k8;7q`mHx9kpZL5xx@+4zM_CTb(g))E?mnm->6Y zz%Qfx4ryOe+&3dx;ICb_3{Q;}o4D{_6GfGO+$dI45Z9=9rmG&-aV&}Ix|WEp{d(!! z39&WIhk-^*lt1frnYmBkJCx+{t6)*rh2?FvK7S*v+$gevv)A%#%9cUdGrb zWh&XBo()kV38_$bdq~S7slnFBQMp9Q^;_J{lL|zOzazC8b!pi{l9W1iJjK(pSe9V5 zYuPPQFAbWOBP&ZKg;y3Ry-W!+X^r~R%*3wN*rggZ@VH36WaoX&(Icam& zX3}KJTjVLTue`dgO=Vn4i6o8?O3V>&L45nMtzj(pONzUvjq+-rXivr2iiI`*|2ZPk cBs#}*VGpiwi@7mY?|(+;-jBlpGZ;JgFFtqVcK`qY delta 1090 zcmX|;YQ5lH5v}W_>dQXsthN6CU+dp{ zd;6aD@p;NybLG%Axxsv4L!F(I^b*aALcESw=Le`UES%s%sti%rrPv3viO-BC0WdO7YqGEeL-COYK#7+ z$Nfp~9~PJ5_VA}Z;cxXE<}ZuCnbmPC)v7Gzu%Xp`xng%QU&!|5uFn?l4&r93N4XS6 z@0|%BYm{m68f!hutB-jbbjg}_1Ty=2s@A#YpF@;7E+j@9=aS|;{YEfb)rf}#K^71p zsh5QgF71%a5(3f@Wf|vl5e-~IiWMx9@s_iai|Hgo7u{SzmQ@tEiu=jv^chDRZxD31 zaNQ)xTWDqt?eqx8tz1s8pl)L|w@b86uMBVV<_L3_==AAB;ap_BU^g(20m%*u#}IMy z!coxI)m&ZLi-8w7ka(4;&xFw$BaHZey_-HY4r{zEBOKfL9kEt4==@m=1P^}UwCg$BtS}jn` zm{K{Q&Q!JXwWE3!Ly6$HN=nrsvU^lYEfhoJ>`*PLRi6AR234DCm#)=h)grYRx4J;k zHPUZ)rCL;nw9OTlNbzhb#&FDvs>dX3+K-RTCetRzO=k2!?Fu!jU#@K|?GOrafn?$! zi9|>_%gVizc;z0W0pAOFqk*~?sTRvZ%J$Y6bB-Bff-owM)m0XHoNAsRBsSFZl)Onz z6Hm*#eWqeWOcX*y{#{VC{$D>CR!f!aUm4hkahiJNJB4nHw0WNu)1JfPd7X>w`UfJ5 B=~4gy diff --git a/out/production/TestPaperGenerationSystem/AuthService.class b/out/production/TestPaperGenerationSystem/AuthService.class index 4880a956831705b0c3fd31b415656dd7a5699900..bfa23c7d05f09f870d5c21ba3412caa283f2747b 100644 GIT binary patch delta 276 zcmZ3;xr3AI)W2Q(7#J9w7@Q|^#WD-}cuvfeW8(MR*x|(}!Ooz^$iU<2SXz=1oLW?t znVibVAfn;px%oQd8b(P*23-b51|bG+1|FaROh7g(gFcWnm^_PF+R_jx#>c=6B)J(_ zfGRi{co~d{Rf>}-gy{;dm delta 235 zcmX|)O%B0O6ot>NHnc?q(Sf8h2@bDHV77R=+#jNQH%uN~-F|Yt@u>=w4k;qH# zJNJ9vz3*zCOzZK!-2tqzimaVh*hU9e^2u={hM-j6UY>Fm2M`otBTG|bHqc`A;v`iK ze6l=JtTuESCUR)AtIz~2bkOCklA0Hu9{POqVnd&ZABVcLSALVzK;!Q>Fu;(uVk0Jv i^Df2+_}7F~?fQ`^$&4fed7+j@8FO|T7BrUM6n+4|kr<`` diff --git a/out/production/TestPaperGenerationSystem/InMemoryUserRepository.class b/out/production/TestPaperGenerationSystem/InMemoryUserRepository.class deleted file mode 100644 index e398e3fcbd01600a8e689955d4df36ff200c9e80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1474 zcma)6+fEZv6kVr9XBY-3BOn)Vh+tcUQt$${q5^W!0*NRF-=<}NA!VkSPEGs+jRs$Q zFd-zq=!+r2M8nMxpZx)U05rbo4;c5HmZ4BIrs?VIy=JYm_d5IZ%kPaX0KFKK;DJ{_ zk&Gia%HW$*AE}|FYRrVj;&WQUW;hzv4c+cx@cIK20z`&p{!+%)lc9uZBr=wz8Fr}8 zeH>ELvmMUH}qDyl2o(JA6MRl2kCVrTiS1O>HDKXnY<{;Ux1 zXxz4RV&@m(LoOFQ3Z<@^;LnM4WZ|=@4?|&ZMfjbzo-A#zEsF@c08uWu0a4m0_`dLLd*dZh+KKYx-78M%Z~>xR zbc0T(yUQ}Jpo?0W(WsT?Ls~hca0yot5fGJe4Kx$Vo-Jc3TQ?0g$sn22qnTtsL2V{(w#V$EV5_yG(%17@bM(QvT5Cz>g8i=sPhN=%59%tpxYON=*)JO zr4-i8(4KG6Kcu2Dw>@dx%vcF+KzA&zKfLNT=WNhG7tjNS>-1HeOGv*r>F#^z_B(mH z_O$i^Y>@6NBji_b6)d<3VR9A4A0Y)lKvI00P$m_hQmIt0qGlcSUOeDH0|y!kfkqBA z76MHiXd>YJeyIQl0);>e2U-e&Rt~fh5ZW&l=0La*=;T1>KHxpKqo39e$h4NCh)gSo z4}MgTSqdJa5@}T7IjZpnHP}KezM>94QIA{1kh8{N0D}}U3}KkeB~uCY&|Av}9xF?t%|ywN|+|9Tq$ diff --git a/out/production/TestPaperGenerationSystem/SessionManager.class b/out/production/TestPaperGenerationSystem/SessionManager.class index 32dc1bc157729229ee79f994a692e0d89ab873d2..6edfdbf6302f8358bdc47f8aa67a5570329143c6 100644 GIT binary patch delta 262 zcmWNMy-LGi7=_Q<{CsH)MWHRYWGO*(u+HM5RsBT z@B+HJcm)n#fP#bg4Tp0c4re&C#%E(~_V@Y*U<(g6D$oRU2L?<+b2G?`O!kX|Fwf&r z>dRC{VfMW8q}AsWIg#z5Orv%;NWy+0a8!P1F42g8bhmb8BSS7wIM~NEw~TlFhTw76 z@JxX_f~%s-+vazz*AY1Ug$}|oPIy=N)l)1eBAoG~*wZ8e{t`YHR+D{eNegk#Q)`_f yezAHqD4psm%?+@u1_nyRykoa0;n?2rF4VCKhPYI2seY`KVxq`aX^LCiWAPt)IX%?? delta 261 zcmaDRdP-F5)W2Q(7#J9w7^=7!m>8JZ8CZB2SQ*$D83eKt%M$f-67$ma{gbj%lS?)l zY+&B}jai0KH+EqlJU^ZBmjRtk*#Yz+Ba34qxU(hNQ`199ENqIm9L}<4|WzoqUcXk}++w2B#h) zcN&8xPy;K&W`^|1iCoHz8IxPNY*aIW{$gUtV#o&496rm&C?GBEDZPz*oR zV(4hrmBN?&H5}E7@^Mu`{5!h&?BVH{XN_yYnVNnAIWvz)JI(`g&u9Z4Vc+wmf&!mb zEX+cO5hHt$LodH~5&-(p&l97N=S38Eg#m7rxQ$XoyNei%c88x@*HwhoV`*EAN^GfL w6k#aQvdU#ugiLWZ`;MC=Q)0INF{>DkRU;VXnql)eKVz8Y$>45=k?I@@KQG`_X8-^I literal 1758 zcmaJ?TXWk)7(MHo99OY(YtjozTbdSIPGc_R5?l(@B{bkbXI#PnPaAuQ)hLp&)?vyI z;5YCG;3*F+duTrfj2P0L6g}!*7FO&lsm|%owBHQ(w!Gr`u{@c{8kQ&c<2H3oPu(UDXQw zuGF8qy3bvxrLRMQ>($eFYNt&m%Q+k8O_npE4u*0^-Iuy=y1r=R1uU|p9i>|y%MzHa zrej3LW(k*Y*}@eYFXHMkg5vf_kosmMJ;KkXi;C%M*1jy^8m?P-$wn15f$4~!k#@a= zVFGh~8TJL{t6!yBcotwoU@aXuVKwFXzn0n-W4D4Hb*Z#nUwty#+g8H|a@&iP3cAwU zl0(;=6Jt*IT^3Ym8)2IyjpUeZEbiPfev-7Y)BQwOW+LQnN>G6^EuACs1w?RsP?AYDJOk4c}M8Xk1lj;hw;?Q$39< z)xt*tOV4*Tvk>)#E4)h?Ud|jZEiXTJGv-c5E3a|1@}hCIAow+L_^$Kx9Z@;1OU`c) zPW=#;vvP<@=f)wXoca^Y0*6@mg&rBK@O=RVzRSc^Fo7xVrs*?_Ma3W3 z@M~kiQzyZf#)5B-1uvWgUmXkPhl-6D?!RY~S*|sw{uA=KgZf`6JCAXp&gVzuvj_D* zQQS0ytnhh^r2{%=Q!-R3WQ~H>F;D9`GP6k9jSQFL!2iim!|Qm1X%|WSoAk-xEqdko z=TbJjui@>arZwtkbg1N>BJ)MoB=7u=Ws^Cr$jwx1l_X0R&B*H(-r-tgnD_YH#yU?W M?mol@KF0Zf0r~1`1poj5 diff --git a/out/production/TestPaperGenerationSystem/UserRepository.class b/out/production/TestPaperGenerationSystem/UserRepository.class index a296ed8bcf25d2e34603ce49db4be7bcb4ac6961..621f0bb952838588b6f7b1d5b8e2c6c0777385f9 100644 GIT binary patch literal 1451 zcma)6+fEZv6kVr9XD9=d;UX7rh+qpsY4HNKq5^VJE{P}x-=<}NA!XW3XH575jRs$Q zFd-zq=!+r2M8nMxpZx)UfNFfxA29AYEkjGun5L(*_nNiN-s|ksFTb~U0rX+Q0~g!^ ziX#@>mJP6@4x+5nWJYCd2WFrfX&|gWKny5+E|P@Rux8iw9x}J!Tn(s+)m+ z=W$p`&5tQb4+OZ2Q36Rosf03=Gn73@sm47unMi47!dPOEEJ_S0rV>?BDnt3`fi_8m zMN}{d=})isHlGFsR5BFV3L>hho?xg;#0jb}z5XJ-_SOR#b#@>13_ZS#5btEtG&FrK z{6880R0&Svlz`I`&fqLVXGH)ZtKbF-sYN!RtF%;MJFIi2L<1kpY3hGBuXbye!P3dDIo_S$|Wc0vb(z? z;VQbRl{uAKX*r^mBMSH68o~l160U=0K|Zi$B57&~U5PVz60_r0Jg!9JbdtWm>+;Fj zr;+GQI`@&ogHb%G&FPA18Kjl1hx2GEB00Y9pRG*~_l9Xc`V%vJkThK#w-%$SaX(X# zJer6p@hQd7>^Pe&GUv4vjs0l;_M}rbtLZa+OLksY77sU+-8Q!{ry&N>a#(U+uO?gYCG)1KqK8W7Z`5PSGI2({obNW?xJgM=jnda+7GZH zx|ocRU#%Nptve8=H&FZ$p4JcW$le{u)3R5tl4~|lyM+cf9&(_O1C51169<|Kfo2Xg z6L2A4%Fh9RA<)KwwnCtt1MLI^@}+_t2o?fe9O%je-g7$!XbnN4wG>5US~Kk delta 115 zcmZ3@{e#iu)W2Q(7#J9w7`WLPm>3!OLW@(2f>I0ei!)2|iz?X}SQr@uvJ%S@^>Y&Q z()In5vQm>vCMz=Aad8G`rspM=loq8 login(String username, String password); +} \ No newline at end of file diff --git a/src/IUserRepository.java b/src/IUserRepository.java new file mode 100644 index 0000000..c22caf1 --- /dev/null +++ b/src/IUserRepository.java @@ -0,0 +1,16 @@ +import java.util.Optional; + +/** + * 用户仓库接口。 + * 定义了访问用户数据的统一契约,将业务逻辑与数据源解耦。 + */ +public interface IUserRepository { + + /** + * 根据用户名查找用户。 + * + * @param username 用户的唯一标识符 + * @return 一个包含用户对象的 Optional,如果用户不存在则为空 + */ + Optional findByUsername(String username); +} \ No newline at end of file diff --git a/src/InMemoryUserRepository.java b/src/InMemoryUserRepository.java deleted file mode 100644 index 9e3f5ba..0000000 --- a/src/InMemoryUserRepository.java +++ /dev/null @@ -1,33 +0,0 @@ -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 用户仓库的内存实现。 - * 在程序启动时,预加载所有预定义的用户账户。 - */ -public class InMemoryUserRepository implements UserRepository { - - private final Map userDatabase = new ConcurrentHashMap<>(); - - public InMemoryUserRepository() { - // 初始化预定义的9个用户账户 - // 小学老师 - userDatabase.put("张三1", new User("张三1", "123", "小学")); - userDatabase.put("张三2", new User("张三2", "123", "小学")); - userDatabase.put("张三3", new User("张三3", "123", "小学")); - // 初中老师 - userDatabase.put("李四1", new User("李四1", "123", "初中")); - userDatabase.put("李四2", new User("李四2", "123", "初中")); - userDatabase.put("李四3", new User("李四3", "123", "初中")); - // 高中老师 - userDatabase.put("王五1", new User("王五1", "123", "高中")); - userDatabase.put("王五2", new User("王五2", "123", "高中")); - userDatabase.put("王五3", new User("王五3", "123", "高中")); - } - - @Override - public Optional findByUsername(String username) { - return Optional.ofNullable(userDatabase.get(username)); - } -} \ No newline at end of file diff --git a/src/UserRepository.java b/src/UserRepository.java index 4ab7ee8..0812340 100644 --- a/src/UserRepository.java +++ b/src/UserRepository.java @@ -1,16 +1,33 @@ +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; /** - * 用户仓库接口。 - * 定义了访问用户数据的统一契约,将业务逻辑与数据源解耦。 + * 用户仓库的内存实现。 + * 在程序启动时,预加载所有预定义的用户账户。 */ -public interface UserRepository { +public class UserRepository implements IUserRepository { - /** - * 根据用户名查找用户。 - * - * @param username 用户的唯一标识符 - * @return 一个包含用户对象的 Optional,如果用户不存在则为空 - */ - Optional findByUsername(String username); + private final Map userDatabase = new ConcurrentHashMap<>(); + + public UserRepository() { + // 初始化预定义的9个用户账户 + // 小学老师 + userDatabase.put("张三1", new User("张三1", "123", "小学")); + userDatabase.put("张三2", new User("张三2", "123", "小学")); + userDatabase.put("张三3", new User("张三3", "123", "小学")); + // 初中老师 + userDatabase.put("李四1", new User("李四1", "123", "初中")); + userDatabase.put("李四2", new User("李四2", "123", "初中")); + userDatabase.put("李四3", new User("李四3", "123", "初中")); + // 高中老师 + userDatabase.put("王五1", new User("王五1", "123", "高中")); + userDatabase.put("王五2", new User("王五2", "123", "高中")); + userDatabase.put("王五3", new User("王五3", "123", "高中")); + } + + @Override + public Optional findByUsername(String username) { + return Optional.ofNullable(userDatabase.get(username)); + } } \ No newline at end of file From f2970a1ee2e885a84ecd02f3f7fa76efcca24b9f Mon Sep 17 00:00:00 2001 From: Teptao <1650163832@qq.com> Date: Thu, 25 Sep 2025 19:14:36 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A2=98=E7=9B=AE?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=99=A8=EF=BC=88=E6=96=B0=E9=9C=80=E6=B1=82?= =?UTF-8?q?=EF=BC=8C=E5=B0=8F=E5=AD=A6=E9=A2=98=E7=9B=AE=E4=B8=8D=E8=83=BD?= =?UTF-8?q?=E6=9C=89=E8=B4=9F=E6=95=B0=EF=BC=89=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8B=AC=E5=8F=B7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AbstractProblemGenerator.java | 152 ++++++++++++++++++++++---- src/Application.java | 1 + src/ElementaryProblemGenerator.java | 39 +------ src/Equation.java | 79 ++++++------- src/HighSchoolProblemGenerator.java | 34 ++---- src/MiddleSchoolProblemGenerator.java | 29 +++-- src/Operator.java | 42 +++---- 7 files changed, 210 insertions(+), 166 deletions(-) diff --git a/src/AbstractProblemGenerator.java b/src/AbstractProblemGenerator.java index 4c84464..9576e3d 100644 --- a/src/AbstractProblemGenerator.java +++ b/src/AbstractProblemGenerator.java @@ -1,13 +1,15 @@ import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * 抽象题目生成器(模板方法模式)。 - * 实现了 IProblemGenerator 接口,提供了通用的题目生成逻辑, - * 如唯一性检查循环、操作数生成等,将具体的题目构建逻辑延迟到子类。 + * 提供了生成题目的通用流程和创建基础四则运算的核心方法。 */ public abstract class AbstractProblemGenerator implements IProblemGenerator { @@ -17,51 +19,153 @@ public abstract class AbstractProblemGenerator implements IProblemGenerator { protected static final int MIN_OPERANDS_COUNT = 2; protected static final int MAX_OPERANDS_COUNT = 5; + private static final Operator[] AVAILABLE_OPERATORS = { + Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE + }; + @Override - public List generate(int count, Set existingProblems) { + public final List generate(int count, Set existingProblems) { List newProblems = new ArrayList<>(count); - // 使用一个临时的Set来防止在同一次生成任务中产生重复 Set currentBatchSet = new HashSet<>(); - while (newProblems.size() < count) { - Equation candidate = createProblem(); + int maxTries = count * 100; + int tries = 0; + while (newProblems.size() < count && tries < maxTries) { + Equation candidate = createProblem(); String canonicalForm = candidate.toCanonicalString(); - // 执行唯一性检查:既不能与历史重复,也不能与本次生成的其他题目重复 - if (!existingProblems.contains(canonicalForm) && !currentBatchSet.contains(canonicalForm)) { + if (!existingProblems.contains(canonicalForm) && currentBatchSet.add(canonicalForm)) { newProblems.add(candidate); - currentBatchSet.add(canonicalForm); } + tries++; } return newProblems; } /** - * 创建一个候选数学题目的抽象方法(模板方法)。 - * 子类必须实现此方法来定义具体难度的题目生成规则。 - * - * @return 一个新创建的 Equation 对象 + * 模板方法:创建一道具体问题的抽象定义,由子类实现。 */ protected abstract Equation createProblem(); /** - * 生成一个在指定范围内的随机整数。 + * 创建一个基础的四则运算方程式。 + * 此方法已被重构,将复杂逻辑委托给私有辅助方法。 * - * @param min 最小值(包含) - * @param max 最大值(包含) - * @return 随机整数 + * @param nonNegativeOnly 如果为 true,则强制保证所有中间和最终结果非负。 + * @return 一个 Equation 对象。 */ - protected int getRandomNumber(int min, int max) { - return random.nextInt(max - min + 1) + min; + protected Equation createBaseArithmeticProblem(boolean nonNegativeOnly) { + int numOperands = getRandomNumber(MIN_OPERANDS_COUNT, MAX_OPERANDS_COUNT); + List operands = new ArrayList<>(); + List operators = new ArrayList<>(); + + int currentResult = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE); + operands.add(String.valueOf(currentResult)); + + for (int i = 0; i < numOperands - 1; i++) { + if (nonNegativeOnly) { + currentResult = appendNonNegativeOperation(operands, operators, currentResult); + } else { + appendStandardOperation(operands, operators); + } + } + + addParentheses(operands, operators); + return new Equation(operands, operators); + } + + /** + * (Refactored Helper) 追加一个确保结果非负的运算步骤。 + * + * @param operands 当前操作数列表 + * @param operators 当前操作符列表 + * @param currentResult 当前的累计计算结果 + * @return 更新后的累计计算结果 + */ + private int appendNonNegativeOperation(List operands, List operators, int currentResult) { + Operator operator = AVAILABLE_OPERATORS[random.nextInt(AVAILABLE_OPERATORS.length)]; + int nextOperand; + int newResult = currentResult; + + switch (operator) { + case ADD: + nextOperand = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE); + newResult += nextOperand; + break; + case SUBTRACT: + nextOperand = getRandomNumber(MIN_OPERAND_VALUE, currentResult); + newResult -= nextOperand; + break; + case MULTIPLY: + nextOperand = getRandomNumber(MIN_OPERAND_VALUE, 10); + newResult *= nextOperand; + break; + case DIVIDE: + List divisors = findDivisors(currentResult); + nextOperand = divisors.get(random.nextInt(divisors.size())); + newResult /= nextOperand; + break; + default: + // 为了编译安全,实际上不会执行到这里 + throw new IllegalStateException("Unexpected value: " + operator); + } + operands.add(String.valueOf(nextOperand)); + operators.add(operator); + return newResult; } /** - * 从给定的操作符数组中随机选择一个。 - * @param availableOperators 可用的操作符数组 - * @return 随机选择的操作符 + * (Refactored Helper) 追加一个标准的运算步骤(允许负数)。 + * + * @param operands 当前操作数列表 + * @param operators 当前操作符列表 */ - protected Operator getRandomOperator(Operator[] availableOperators) { - return availableOperators[random.nextInt(availableOperators.length)]; + private void appendStandardOperation(List operands, List operators) { + Operator operator = AVAILABLE_OPERATORS[random.nextInt(AVAILABLE_OPERATORS.length)]; + int nextOperand; + + if (operator == Operator.DIVIDE) { + // 为确保整除,反向构造 + int divisor = getRandomNumber(1, 10); + int quotient = getRandomNumber(1, 20); + // 替换前一个操作数以确保可整除 + operands.set(operands.size() - 1, String.valueOf(divisor * quotient)); + nextOperand = divisor; + } else { + nextOperand = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE); + } + operands.add(String.valueOf(nextOperand)); + operators.add(operator); + } + + + private void addParentheses(List operands, List operators) { + if (operators.size() > 1 && random.nextBoolean()) { + int pos = random.nextInt(operators.size()); + Operator op = operators.get(pos); + // 仅在优先级较低的运算符旁边添加括号才有视觉意义 + if (op == Operator.ADD || op == Operator.SUBTRACT) { + operands.set(pos, "(" + operands.get(pos)); + operands.set(pos + 1, operands.get(pos + 1) + ")"); + } + } + } + + private List findDivisors(int number) { + if (number == 0) { + return Collections.singletonList(1); // 避免除以0 + } + return IntStream.rangeClosed(1, Math.abs(number)) + .filter(i -> number % i == 0) + .boxed() + .collect(Collectors.toList()); + } + + protected int getRandomNumber(int min, int max) { + if (min > max) { + return max; // 安全处理,例如当currentResult变为1时 + } + return random.nextInt(max - min + 1) + min; } } \ No newline at end of file diff --git a/src/Application.java b/src/Application.java index 4ed397f..30e86ff 100644 --- a/src/Application.java +++ b/src/Application.java @@ -128,6 +128,7 @@ public class Application { System.out.println("正在生成 " + count + " 道不重复的新题目..."); IProblemGenerator generator = sessionManager.getCurrentGenerator(); List newProblems = generator.generate(count, history); + // 命令行显示生成题目 for (int i = 0; i < newProblems.size(); i++) { String problemLine = (i + 1) + ". " + newProblems.get(i).toString(); diff --git a/src/ElementaryProblemGenerator.java b/src/ElementaryProblemGenerator.java index 50cef20..26e8a0b 100644 --- a/src/ElementaryProblemGenerator.java +++ b/src/ElementaryProblemGenerator.java @@ -1,45 +1,12 @@ -import java.util.ArrayList; -import java.util.List; - /** * 小学题目生成器(具体策略)。 - * 生成包含2-5个操作数的四则运算题目。 + * 其实现委托给基类的核心方法,并强制要求结果非负。 */ public class ElementaryProblemGenerator extends AbstractProblemGenerator { - private static final Operator[] AVAILABLE_OPERATORS = { - Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE - }; - @Override protected Equation createProblem() { - int numOperands = getRandomNumber(MIN_OPERANDS_COUNT, MAX_OPERANDS_COUNT); - List operands = new ArrayList<>(); - List operators = new ArrayList<>(); - - // 生成第一个操作数 - operands.add(getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE)); - - for (int i = 0; i < numOperands - 1; i++) { - Operator operator = getRandomOperator(AVAILABLE_OPERATORS); - int nextOperand; - - // 特殊处理除法,确保除数不为0且能整除,避免产生小数 - if (operator == Operator.DIVIDE) { - // 为了简化,我们让被除数是新生成的随机数的倍数 - int divisor = getRandomNumber(1, 10); // 将除数范围缩小以增加整除概率 - int quotient = getRandomNumber(1, 10); - int dividend = operands.get(operands.size() - 1); // 获取前一个结果或操作数 - operands.set(operands.size() - 1, divisor * quotient); // 替换前一个操作数确保能整除 - nextOperand = divisor; - } else { - nextOperand = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE); - } - - operands.add(nextOperand); - operators.add(operator); - } - - return new Equation(operands, operators, true); + // 调用父类的核心方法,并传入 true,要求启用“无负数”约束。 + return createBaseArithmeticProblem(true); } } \ No newline at end of file diff --git a/src/Equation.java b/src/Equation.java index 3bf80a9..76fcd70 100644 --- a/src/Equation.java +++ b/src/Equation.java @@ -1,77 +1,82 @@ -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * 方程式实体类。 - * 封装了构成一个数学方程式的所有元素(操作数、操作符)及其行为(计算、格式化输出)。 + * 封装了构成一个数学方程式的所有元素(操作数、操作符)。 + * 操作数统一使用 String 类型,以支持数字、函数表达式等多种形式。 */ public class Equation { - private final List operands; // 使用String以支持如 "sqrt(16)" 的形式 + private final List operands; private final List operators; + /** + * 构造函数。 + * + * @param operands 操作数列表(可以是数字、函数表达式等) + * @param operators 操作符列表 + */ public Equation(List operands, List operators) { - this.operands = new ArrayList<>(operands); - this.operators = new ArrayList<>(operators); - } - - // 为了方便,提供一个只接受整数操作数的构造函数 - public Equation(List intOperands, List operators, boolean isSimple) { - this.operands = intOperands.stream().map(String::valueOf).collect(Collectors.toList()); - this.operators = new ArrayList<>(operators); + this.operands = Collections.unmodifiableList(operands); + this.operators = Collections.unmodifiableList(operators); } + /** + * 获取操作数列表的不可变视图。 + * + * @return 操作数列表 + */ public List getOperands() { - return Collections.unmodifiableList(operands); + return operands; } + /** + * 获取操作符列表的不可变视图。 + * + * @return 操作符列表 + */ public List getOperators() { - return Collections.unmodifiableList(operators); + return operators; } /** - * 生成用于展示给用户和保存到文件的标准字符串。 - * 格式: "操作数1 运算符1 操作数2 = 结果" + * 生成用于展示给用户和保存到文件的标准问题字符串。 + * 格式: "操作数1 运算符1 操作数2 = ?" * * @return 格式化的方程式字符串 */ @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append(operands.get(0)); - for (int i = 0; i < operators.size(); i++) { - sb.append(" ").append(operators.get(i).getSymbol()).append(" "); - sb.append(operands.get(i + 1)); - } - sb.append(" = ").append("?"); + // 使用 IntStream 来优雅地处理操作数和操作符的交替拼接 + IntStream.range(0, operators.size()) + .forEach(i -> sb.append(operands.get(i)) + .append(" ") + .append(operators.get(i).getSymbol()) + .append(" ")); + sb.append(operands.get(operands.size() - 1)); // 追加最后一个操作数 + sb.append(" = ?"); return sb.toString(); } /** * 生成用于唯一性校验的“规范化”字符串。 - * 这是确保 "3 + 5" 和 "5 + 3" 被视为同一题目的关键。 - * 规范化规则:对于可交换运算符,操作数按升序排列。 + * 对于简单的可交换运算 (如 "3 + 5"),操作数会排序以确保唯一性 ("3 + 5")。 + * 对于复杂或不可交换的运算,直接返回原始顺序的字符串。 * * @return 规范化的方程式字符串 */ public String toCanonicalString() { - if (operators.size() == 1 && operators.get(0).isCommutative()) { - // 仅处理最简单的二元运算场景 - String[] sortedOperands = operands.toArray(new String[0]); - Arrays.sort(sortedOperands); - return sortedOperands[0] + " " + operators.get(0).getSymbol() + " " + sortedOperands[1]; + // 简化处理:仅对两个操作数且操作符可交换的情况进行规范化 + if (operands.size() == 2 && operators.size() == 1 && operators.get(0).isCommutative()) { + List sortedOperands = operands.stream().sorted().collect(Collectors.toList()); + return sortedOperands.get(0) + " " + operators.get(0).getSymbol() + " " + sortedOperands.get(1); } - // 对于更复杂的或不可交换的运算,直接按顺序拼接 - StringBuilder sb = new StringBuilder(); - sb.append(operands.get(0)); - for (int i = 0; i < operators.size(); i++) { - sb.append(" ").append(operators.get(i).getSymbol()).append(" "); - sb.append(operands.get(i + 1)); - } - return sb.toString(); + // 对于其他所有复杂情况,直接按原样拼接 + return toString().replace(" = ?", ""); } } \ No newline at end of file diff --git a/src/HighSchoolProblemGenerator.java b/src/HighSchoolProblemGenerator.java index 22739ba..ff3bdcc 100644 --- a/src/HighSchoolProblemGenerator.java +++ b/src/HighSchoolProblemGenerator.java @@ -3,52 +3,34 @@ import java.util.List; /** * 高中题目生成器(具体策略)。 - * 作为初中生成器的子类,它首先生成一个包含初中难度运算(平方/开方)的题目, + * 它首先生成一个包含初中难度运算(平方/开方)的题目, * 然后再额外加入一个三角函数运算,使得题目难度递增。 */ public class HighSchoolProblemGenerator extends MiddleSchoolProblemGenerator { - // 预定义一些常见的三角函数角度 private static final int[] PREDEFINED_ANGLES = {0, 30, 45, 60, 90}; + private static final String[] TRIG_FUNCTIONS = {"sin", "cos", "tan"}; @Override protected Equation createProblem() { - // 首先,调用父类(MiddleSchoolProblemGenerator)的方法, - // 生成一个已经包含平方或开方运算的题目结构。 + // 1. 调用父类(已修正的 MiddleSchoolProblemGenerator)的方法 Equation middleSchoolEquation = super.createProblem(); - // 直接获取父类生成的可变列表进行再次修改 List operands = new ArrayList<>(middleSchoolEquation.getOperands()); List operators = new ArrayList<>(middleSchoolEquation.getOperators()); - // 随机选择一个操作数,用三角函数表达式替换。 - // 这可能替换一个普通数字,也可能替换掉父类生成的 sqrt(x) 或 (x^2) 表达式,增加了多样性。 + // 2. 随机替换一个操作数为三角函数 int modifyIndex = random.nextInt(operands.size()); int angle = PREDEFINED_ANGLES[random.nextInt(PREDEFINED_ANGLES.length)]; + String funcType = TRIG_FUNCTIONS[random.nextInt(TRIG_FUNCTIONS.length)]; - // 随机选择一个三角函数 - int funcType = random.nextInt(3); - String trigExpression; - - switch (funcType) { - case 0: // sin - trigExpression = "sin(" + angle + ")"; - break; - case 1: // cos - trigExpression = "cos(" + angle + ")"; - break; - default: // tan - if (angle == 90) { - angle = 45; // 避免tan(90)无定义的情况 - } - trigExpression = "tan(" + angle + ")"; - break; + if ("tan".equals(funcType) && angle == 90) { + angle = 45; // 避免 tan(90) } - // 用三角函数的表达式字符串替换随机选择的操作数 + String trigExpression = String.format("%s(%d)", funcType, angle); operands.set(modifyIndex, trigExpression); - // 用修改后的操作数和原有的操作符列表创建最终的高中题目 return new Equation(operands, operators); } } \ No newline at end of file diff --git a/src/MiddleSchoolProblemGenerator.java b/src/MiddleSchoolProblemGenerator.java index 19ae647..83f57c3 100644 --- a/src/MiddleSchoolProblemGenerator.java +++ b/src/MiddleSchoolProblemGenerator.java @@ -1,37 +1,34 @@ import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * 初中题目生成器(具体策略)。 - * 基于小学题目,并确保至少包含一个平方或开方运算。 + * 首先生成一个允许出现负数的标准四则运算题目,然后确保至少包含一个平方或开方运算。 */ -public class MiddleSchoolProblemGenerator extends ElementaryProblemGenerator { +public class MiddleSchoolProblemGenerator extends AbstractProblemGenerator { @Override protected Equation createProblem() { - // 首先,借用父类方法生成一个基础的四则运算结构 - Equation basicEquation = super.createProblem(); + // 1. 调用父类的核心方法,并传入 false,允许生成包含负数的标准表达式。 + Equation basicEquation = createBaseArithmeticProblem(false); - // 将父类生成的操作数(Integer)转换为本类需要的 String 列表 - List operands = basicEquation.getOperands().stream() - .map(String::valueOf) - .collect(Collectors.toList()); + // 2. 将基础表达式元素转为可修改的列表 + List operands = new ArrayList<>(basicEquation.getOperands()); List operators = new ArrayList<>(basicEquation.getOperators()); - // 随机选择一个操作数进行变形 + // 3. 随机选择一个操作数进行变形 int modifyIndex = random.nextInt(operands.size()); - int originalValue = Integer.parseInt(operands.get(modifyIndex)); + String targetOperand = operands.get(modifyIndex).replace("(", "").replace(")", ""); - // 随机决定是进行平方还是开方运算 + // 4. 随机决定是进行平方还是开方运算 if (random.nextBoolean()) { - // 平方运算:生成 "(originalValue^2)" 格式的字符串 - String squaredExpression = String.format("(%d^2)", originalValue); + // 平方运算 + String squaredExpression = String.format("(%s^2)", targetOperand); operands.set(modifyIndex, squaredExpression); } else { - // 开方运算:生成 "sqrt(value)" 格式的字符串 + // 开方运算 int base = getRandomNumber(2, 10); - int valueToRoot = base * base; // 确保可以完美开方 + int valueToRoot = base * base; String sqrtExpression = String.format("sqrt(%d)", valueToRoot); operands.set(modifyIndex, sqrtExpression); } diff --git a/src/Operator.java b/src/Operator.java index 8597142..2af0b79 100644 --- a/src/Operator.java +++ b/src/Operator.java @@ -1,54 +1,42 @@ -import java.util.function.BinaryOperator; - /** * 数学运算符枚举。 - * 封装了运算符的符号和其对应的计算逻辑。 - * 这种设计符合开闭原则,易于扩展新的运算符。 + * 封装了运算符的符号及其属性,如是否为可交换运算符。 */ public enum Operator { - ADD('+', (a, b) -> a + b, true), - SUBTRACT('-', (a, b) -> a - b, false), - MULTIPLY('*', (a, b) -> a * b, true), - DIVIDE('/', (a, b) -> a / b, false); + ADD('+', true), + SUBTRACT('-', false), + MULTIPLY('*', true), + DIVIDE('/', false); private final char symbol; - private final BinaryOperator operation; private final boolean isCommutative; // 标记是否为可交换运算符(如加法、乘法) /** * 构造函数。 * * @param symbol 运算符的字符表示 - * @param operation 封装了计算逻辑的函数式接口 * @param isCommutative 运算符是否满足交换律 */ - Operator(char symbol, BinaryOperator operation, boolean isCommutative) { + Operator(char symbol, boolean isCommutative) { this.symbol = symbol; - this.operation = operation; this.isCommutative = isCommutative; } + /** + * 获取运算符的字符表示。 + * + * @return 符号字符 + */ public char getSymbol() { return symbol; } - public boolean isCommutative() { - return isCommutative; - } - /** - * 应用此运算符进行计算。 + * 判断此运算符是否满足交换律。 * - * @param a 第一个操作数 - * @param b 第二个操作数 - * @return 计算结果 + * @return 如果是可交换的,则返回 true */ - public int apply(int a, int b) { - // 为除法增加安全检查,防止除以零 - if (this == DIVIDE && b == 0) { - // 在实际生成中,应避免生成除数为0的题目,这里作为最后防线 - throw new ArithmeticException("Division by zero."); - } - return operation.apply(a, b); + public boolean isCommutative() { + return isCommutative; } } \ No newline at end of file From 73a07cdccf0e106f3510d39f3ed93f48e8818012 Mon Sep 17 00:00:00 2001 From: Teptao <1650163832@qq.com> Date: Thu, 25 Sep 2025 19:54:42 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=E9=87=8D=E5=86=99=E6=9F=A5=E9=87=8D?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BA=A4=E6=8D=A2=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=95=B0=E9=A1=BA=E5=BA=8F=E7=9A=84=E9=A2=98=E7=9B=AE=E4=B8=8D?= =?UTF-8?q?=E8=A7=86=E4=B8=BA=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AbstractProblemGenerator.class | Bin 1931 -> 6531 bytes .../Application.class | Bin 6663 -> 6663 bytes .../ElementaryProblemGenerator.class | Bin 1745 -> 460 bytes .../TestPaperGenerationSystem/Equation.class | Bin 3908 -> 2428 bytes .../HighSchoolProblemGenerator.class | Bin 2069 -> 1854 bytes .../MiddleSchoolProblemGenerator.class | Bin 2785 -> 1944 bytes .../TestPaperGenerationSystem/Operator.class | Bin 3235 -> 1395 bytes .../TextFilePersistence.class | Bin 5948 -> 5176 bytes src/AbstractProblemGenerator.java | 2 +- src/Equation.java | 19 +-------- src/IFileService.java | 2 +- src/TextFilePersistence.java | 37 ++---------------- 12 files changed, 7 insertions(+), 53 deletions(-) diff --git a/out/production/TestPaperGenerationSystem/AbstractProblemGenerator.class b/out/production/TestPaperGenerationSystem/AbstractProblemGenerator.class index c250617a43d56e683aee4feebe042dcf22ccd818..d2cb979340a70eff3691c89b04f6adeb631436c6 100644 GIT binary patch literal 6531 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 Klo8Oafvtb(U3_8y diff --git a/out/production/TestPaperGenerationSystem/Application.class b/out/production/TestPaperGenerationSystem/Application.class index 6c60d237acbf2e5ce50a8ccd6c1b4ae69a04fd44..50bfdb8aded7e5aab38b8a027e0feaf5d3d0c9bd 100644 GIT binary patch delta 71 zcmZoSX*b!hLR_(xp@N}}VG=_-!z_jlh6N0*49gh08P+lMFzjOJWjM*uH~FOaW5$V- b*GhykPMypw8Ob@5fdi0^>s23rG0C)g}0FnTP0Ga@Y0H6Sb0Hy$n0ImRw0J;E-0LcK2lgSt3 d0g#ie7*zq3lLHx9377x~0GR*`0Gg9!8KOVP7PbHY diff --git a/out/production/TestPaperGenerationSystem/ElementaryProblemGenerator.class b/out/production/TestPaperGenerationSystem/ElementaryProblemGenerator.class index 0fbbb590635ff228f766bc3986b8f7b5e2ca9414..ae02b8b8d8aeabd000be5db7d253ce180a8a32a8 100644 GIT binary patch delta 209 zcmcb}dxn|o)W2Q(7#J9w7{n%WCF@8h7o{eaq&g)Qr#cp8mSp6nmSiRe6y+!7q~ux|j0AnWEr(#^&I(ap)o JAOcn<3IKrX9tQvb literal 1745 zcmZ`(-BTM?6#w01lie&!`KTdKq6G_*Kq%H~Y)M1|N$b`P!6XDjwRK5Wx;1QQvSGvr z#~Gb*rmy`2oauvgeCSl10kNawvk(3~K6I?-ZZ?4yJF|25e4l%M=bZc3zrXzfU=g3n z@W3lVP~d}~VK}wXv>STGUTM@fYR1-8!!jDWU2ib>lcr_b3k=>!v?N19K!mKI2MWWP z4A~l%tv7a0I`(ZEc3!ut^{wUB)`mf$d=XWRsv=G?oW8B^=yNUGtj(nw4SiQLo3@Nz zcx4P=P{e5kFCoY<;Mmo4YjaMuY-5v$5qI=j%gBAkFceXv+6jw94?-9gF{0oMMj1{W z<>G0m61`ew2u6;%<~D8{6+01K4^V|KD|iKG>5{2ZO4U+}TIObMC6iATbNK>8&vh-g z-9{(D@fcU|D$dbWyY+U|457#|n&*0$}#UZ_@;7#r>nU-DR@Nwt3g12#roSWQvDx&@m zASXp4<|$6*PD{7Vx+UW>l6;EZVVH0cb=u0IPPDy``1NRsm;SDT_jujjR65Q1MFmR^ z4u#dlVm`H0R`suk50txUx))vHu|pJrM{d#H*!jVr^TRm?+OL` zmf2(oYcHPC1VeA7Vd%Eu&M$)!iE5qVNG(>)9ka<7fvHsXomSm8Y2u0GimGAJB=uOv z7q-(v&PjE5I>^Q3%GQ>vqsz3FR+Y&9=fPnJbX-Y2^lVAH+nur|pYux|YmvJni3PfO z_=KHv4O(hP-CMBr%I8^q+eJ%CR%-61%Y}NYQ8BKV9NM!lM(;ddER53*c<5E3=YX#b zQC_0yS)ubPadY%%^!H64fc;E_2k+C#)gV`uPNi*tYxsaT0UEL-A!qhC1(Hd2IPH`6 zAtoQAw|s!UtovV%O$+^1Qv8bkLkxMa=8X$MVN|Hz$5+#P2=8NT-Z$dg!^96z$yO%Y zxY!}2SnLqfG*{I_ocG{Q4D92Lc%Ul{ib3g?6Z$PL)`DW({{V`cG478A{oS;)BffV2 zZw2DP~Oxg47n4v=`{6vPX@hCw>}A<{bb5gkI1wm*c67)BCdqzSz&;a9>KYJ}=H z^sIb`bGVBM+`|;UC+i={{vl=@(6;Ff&SDw>q!O{lMrj)gweOo`2@9LuxY;;EJJbKr zf6~rW6g$)D=T3i9r_a5cm<>t&(8=t}J@>pk=Q-!x&0qh#`UAiQ>QRKy7eQDvrEQ|W4W7p}X zVOO29xo7G{%gCE`x|vVr+saauSv)Nm!WoQ4Fs9)wVgiGkPaC>)$XBOkxVl}Iu6tQc zXqc2HLrTwc+S1APZ^dktHWE+J&eeWPl)8HqQgVF_0SB72Uzsh9QzE(I&l({6D` zl5$-`8q3VQVi3_}vXw@lD>4zh+tDmOK*{U-8gAeNnNqE0*kyrh&9H$)S{VdH&B|m3 zu|nz-Yl(H~?6!ssR#|_~@goRKB%7=TjA_OG6p08vr0$mN74|?B>)6nc#XU9#b158E zi;kr#nw8G)OQatO%qFwlE?anLS}-fN?loK%b>UR=t#;KYb01EGXDB|D@2C`WmQ85+LCSEB={M6nMuf&&eQVCT)Z&m+@*<{TR7yh2G& z`kr25?nk7x8eIJy#N0IU13%z-Xc_f|yyF};YTc(rP|{(z%|`ftn|{bQ+XhFe88)k1 zR>AZPPKK7VZNtr4dcAJ&jCKSrcX84yy$GJNE8eWiGsouwb1XuL$7={N`6+?G1GUQW zo!^Pq>xca4@x;c*)XY=kNBJ@2b29Y;BDM4qk>?mmT~*KVU%AnTN4&=n<~`2)6f~T} z1g7zrl7w%JEquZi-86&CHyJjBPbrP_>F?zj+~0dhnGf+Z$_m)#S^`RQC3X5!zhUGT zzJwHj0VSMMK{a2Y8Ps?3Ib}ONos6G$lKM|4yL7_Cmv@QeXJ#vL=YB{0$qSsz_YuJ;;q!uD_jOnuo%LU#40bf87`mTS_psQonySWyA->r9>=)V1~P*II=;bw7B?}A z6;^K*Yy92A9Rl-Q`j#q_@q98x_1 literal 3908 zcmcgu`EwIx7=FGaupwQb1Sld=3nH`)5UApn7KBKl5-nPaIv!-w?|M__i3VH(aRfpACXpn|BtLRYEm82QweQc0W4 z8nzRIf|zvDBCxb0Th+)|`8@p?mYMDxoP)WTr(nK{RxA*RZo8+f$yZ!jMZKh%Ihz;) z*3xxaS}jzuNSe%X^&G2Yx1bG66kMcYDJ~Y6R}CqRh}(8bx>gWa*3lX8=t)xp?#pzX zEF@H1f=dNvX~klGQsA;0{n4`NqEGeti*yUxv0T9l6_;bBz>;d<8s8+WpcMtK4YJYb z?flqcScTOJI#hI`i)l2(@u?*j%+|5Iv@fke?<1PgbiuDtu@>tDlo78s0_%eq8*F@t zfv!l$upS!}bgQ@$R|zbxVyo6$ma=RXtei1wXv2Bk!?z+B$}Mk@0au{l>I$uHOxDUU z$F`P@d`>ULun}Qd`|DI(k2F~x(^>7s9sNyUD(J20Y0r~%v023p*h1b|bluDeto3mP zBBp~LYe103He^)Xh;0H9+qhqM$D==r?E<1*K|ecskL+l6Y79HDQ$-fL*uDfiFj*M3 z@~%NfLfIps+$@mj$ecf56t~c#y|+DzeGIW#8V;)1kJ}i@u{?AFiz?L*rXc|wP;n5q z3(Pg_j8!O<9nRf^hx&j_=1vuN;coVXW4SXe(9v2zW@=8kL?%`S4hh+YJ&is#(InBJR;hDZzP`Mnz3cRO3Nr7Em1D^H zS;N$KmkYysX`h@Bfq2#$(ei^@$(AHbAJa=NW!vgwHCJr# z7J%%5;cQjG#4D5FHk^B|2&`%l24nf1BFm^&e9143K<%OGbw?mP^ELR-p%2-dg{2# zX=$U{2rI#lb4ww(`z09IH}Y86!Mj9Ww^wE@YrI_ayEjmgprpodA4lomz4Ss}*fvOt zA2y@q^8<#Xr%B1N7(T{v1)s=M?^BLp10^2q-a*(`A?2O_o(8|%2QS=J^(k?X`b|?W zW%8PB>$ZXuJQf;qYF04?Uvlg&tje#qS6(dV4Kc*4TnKS_v*dT9;Og`Z1Y!PO(sdf5>nxO^#0U~tS%3T5rVN=rX zIe~*RcXa22kSiHJgb7O9T!`|WNf6#Ui!u-Dy)Ll(d|<~IL&jR~0!vO~vA`KD1Ez6V z2vfLX8p#lTLfb!JZKIbZyr*7-6tBq=YnSJD2J3oEx&$$nk5#Vj#{f<|OUBX}btiPsc~#W&bE;k2UoZZ{nx@ynY_1 zAKr=hl;!=Exytg|XR&eUG_J`eC9v=`u9e*NoWiF4;obyg@o8)oIF6oVypK{TN%&ej zPT{6g*zL;qyY`95-9ZmWLgK_<=aTWgG>i{OpUG3WRi^GW%?d=hPV%`17xUuXiFLe> zrEojf!`Q%P=$>h!1p3&MM@Sk$`vgUK6g-Kin9|dfstEmogo2IYH*BNqnM$&v*H3n8 zCZEVLY?qr#!c1l8D6XPN4WC2LH13czXxZcxMv~#~I@Oz!k?u1vfRq0Ndo_%$LklzQ zMLRZ=pBs47-GaT$c8KhZV>_F32acj2-*EjMcDn4zw%$OCXUVCY{wj}CK957Z;8uB@ xkMQr<`v;a)s0`yd1`XkPyujZ$SMRWZFXCmqfsg3&Eqq3KjH}P_1-`=4zX7~;{09I4 diff --git a/out/production/TestPaperGenerationSystem/HighSchoolProblemGenerator.class b/out/production/TestPaperGenerationSystem/HighSchoolProblemGenerator.class index 28c410ea916b1c71a6c3523c47ac0ef19fb699c8..75998fb4405d7746b2bd61096bb53f65bba63be4 100644 GIT binary patch delta 892 zcmZ8f%Tg0j5IuJ$GdE1eI0Svy+xPV8)AzMj@+x0`eJTMM#FGuB#EMl2 z;)05c=w$FtBx0kpBa`u=iI^TwGStkBEt#ukc-hRR!^uKElTAn6=w=WLW>!HjE^%B| z(T50w_J1aWY&~Bwmu&`r^AQ|thAM9;H&2Hilr|y)HcUjj?_8Gh?aSds2IgfVzijcKQ#*seFu!3@2)oI zC*z6-jku-aHpZMfp<9ltkf1vW;k?g{acbDkWZfW1#QB`k|jO7 z_AGDNb|#l~EHUSN6C*{OC1nLtS|A@n2SvfM%;ZHdLYK)-&?-!xk(XMx!8RxmFiEz2 z3{+u?tXfIHH15&LMY{^^&}FtjKyKQ5MVI;5E<8rt7LIMB#!=-^@jb$=9}pl{+Co!j zMD}$BP9d#H$0CAkcEKV0Ok26>&WnbXjej|wr*@H$Tyo7-i zwNi~DW^kWcuZN8X6o~}3fQJO*BFH2jQ6v%YAWY1WIP35e`W!fA0kw3qf?*wEETSkP zO@~3S-;~Qaf*f9sM*11!^ejMh9v=>3oJy6y9`|R(5JlZ^X$`s|X(8Q^wSL{;T1wwU po4ki!L-gGxv3!Z7A^EzJn+TT&$My%O5Cf1n4e*rbmZ61!r9V4KqhSC5 delta 1051 zcmaJ<&rcI!5Pe_U-L0j;(%2G8KnTAHND&02;13W41Vup*RCH|@S}D6tcO^D4>A`~@ zO;!^VFIYrlsnZDG+L%Y@5EVZmL~rRbT6xv$83DEf$18 zGzb@>WvD}+AN?4xUG83a&<_bQd&u2vTkeI1a?;nv?q;%@X{HQaAh<7={n@=~$2}Wv z1sCmuu8{rJGmsYuj2MPxT3IzSqghEKVS2GBAe$+@RkV4rL>xEF0=`PjZix@dxbDLW zZYa3vC{qO*|Ms5JH;r|zB%vsFT#Z{sHYf13bx&idsUovjc|z3_Y0Ye$HjMQ1I^QG{pnoiH9EG;JBpVW0NJDOHaQ!^DL1e*3W`mgc|Rt0MR zPvtm@y`mlw?g(LSD}qiO;l|y>5@gyTJ1T{Hh8c4_-~dk0`U_aXNt~kRVbtev0r8Ta zm$Bz|P8!a)zd@D!7EOI}NPfjA(8G_#3Qskyld~lx?Vt-7R9>LL!6Z4jG9(3-x1a<% z`y?ma>x4T(o+{-%j=8b;0p&{_o$qk`HIsPYG&zC*ZII1}P=S0HHPqCBY97|&ETtyU zfDJSvgJ$H=f_rGgeYE2NS&#TTu1N1^LFYN_{pee=zsZrYZF-_GoZ<%kOgzV!3-h?l a-$V4Tk+D#)R|<9+w|L_0G!6}GsQLx|5!BZJ diff --git a/out/production/TestPaperGenerationSystem/MiddleSchoolProblemGenerator.class b/out/production/TestPaperGenerationSystem/MiddleSchoolProblemGenerator.class index 78a2dd402f4e7a1501c5b1a34e742e2c24c647af..3ac3c68c0f0cf9f96923f5d6598ae27e1bf9138b 100644 GIT binary patch delta 1115 zcmZ{j&u<%55XV2yUVAsrI(6K*6%k7R_zT%IK7-HT-w^U+)BMRt<$GCx^BH|<+j~QH8ZDCFWWC>fr;P;TCKH_X2K|ZVV~R+JUA1cE z+@kALYGs2-g-RPdp&&$#yvb8MtRdN@jT?&o!*=Fs zu3fer?-zf{i12!QHcQ@5+K0Of$G!7`ufwk8{5_c3s`q=~izZ1Kj!&)?VpaP-iCvbj zoUEcDf$To&+fMimvF$KIc~h*}1@IQPN7d0NA~uz{uX-S0pX=HEspFH zyZX={6n{Q@ugS>x0VfnKQh9AWrX6s`$B*Qq=c13dcryA-XPF9Q?=jM1`csn8=e6&d zS@I7B7VmRmDk!9(-~pHY-294j*+3-J;^llWCeK=4k1ll4G5tQTbO=V9U~~x&nnaey zC-%AdO{ar)hg0;44NIpHqVzM$fLys4R~QuChbc0`25~kevcn1PkiZieKWD6?%5AxK zMfv?Ku|YwkD6uNu9l_h;>4NU%wnPnRviDHFAYW2uO$3bcF%{Nj9;1B3JL37JfDfn& zS(7qWBz;i?u1T541l7gY|G{qxeoJD*`2LhCgF1#zL?3}{(!%KY+3`22&)IC-4P~m+&hDP`UZ3ZE&ztk--*9p;0vr2Gy{ucF=FFUP>=7z3|lp6v+4jv1EW9T%uirH79n*E~J2 z5KvR;eBaec%`jYNSikXn>F>qO6Q;ltPH&gJ1*(8B(P|=2s0#U6}F=qs}*65E;T1A;^ z=2Y;(z?-o}LA#2rctBwNQs5fjWTLE91P-S{nJ@Pi##LiaZnk5Gf({isv5PR4#p$(8 zQ!kQz5)|`n$%;UGP4~L<6iv+<%M6TMVaTk4E`c>m z8J%<-ZAK;_3%XB5Mpjc@D4|R-fju}N8|k1xTR2>ho9u@4Py-I(AqCwk9>!sT&HYBH zWa@?DxNV#F={eaQHcOlgQGDLt^V{R7iY$%^L|o%V-S5m?0>^Pe!J{fpqDP=*2}0G5 ztXTTAm$OJ^B$Z3&WSc#vq7SF&fPe&Axm}G{%gC7pcm8(4a|~-NfyeQLg1m};oE2E@ zhx6r(ppWT1IPr?+xVj&(HQ*)WAe;76KBwYIoad>K$@P#7U9)^Z7vmUY^;0`bmk*{D z4AtaNEtbsTX%)k`NN`h{IjIkf3aqO|5v0SWJB?>lJd4ZpI%+#*jfjujC$CG(DG0Mt zh3{A4c@-K)n5`?>+nvg-Y#DS|f}K!Op@X?LllN+Q&Q6v`Bx%u9j~|6mhF-;I+L?X`ZNc#?HFT*C2_JR*b%j$XDSQ8JMQs% zEL6at&c}&+^D;Gmelv7dikk|aR-EY9Dgm8|f<5UJ^;3oxJNe-ghK>d3~@7okMOaA zPgH!0&jhwFop-~UvM2ORUMr83Gy>2@H95NZd(&7Bul@?-35=?E&v3Ary4#Vr?TN`s zc6kv(J2i%bEM-{z{|l=jSGEl^5qR#^OtWBkI;*bcEM5_MP0e+6SHYJ8JC|{CKX?kh z=22T&l@qGU1-5Zm)bXbrd~!G-#;3_uhHt@lwDUH^&%U_Krxb&?6N^u^ssI}mt|Icz z!W|lmALyuod%w_F$?us(<2+Ui+`)Qa9-Hbghi&uNU57uA?7xdW!&KRO8~e|8{)z{? z=5a(|7LRmCx>_Ui=#^@x=aB1;O7ScPZlNPti2R19hU;6SbGT5L!=-nyu`11#&_{DZ6nO0h*$U(#jCVl zN3E*q10?Xktj*@jLhj?v3ZYnS^MZ#l3UyJ?Gwc&;2m+%W;l>fBOMo1#7!bL#+3= zwyNEBdpium)=on})NM!y0yBAB#H_$@@yW|zC-66dPSdZ2o2^cBX{}l>J++auk+*S1 zqp#($fW_#IH5Q#%@4Q^C)$9b}_9i>ZqDBkknvJmbs{Nw7Az&3tRb%VXd%5mZ=GkJD zugXS0vwjb16fVx{7&%8Rf_I{zF{dgVLJDmmM;y aXDCXRI-a*N$0JvmOd%HM5mt=`kN*G$U|4Ga literal 3235 zcma)8TUQfT6#foLNC-oTQK%qTRIDTvwwpM$; zw~ze+edgsnU6BsaxS!;6U?6dc`&;It_=gdF_Id;v zyP%tMykL(oK6pW}TJW6-$K>h_b@Z$nBgJ*juThC+&!77kEYT^Qu6v zcT<&YC!ZpDQ?ZE<>Y{`?6M_;&jT{@J@ZpTa&nOtfxNHKaMvKgFSIpA}td@*EXR3Co zz)+5F?y%28RV5iGds&MWe1FoKAyi{pH??!6+_Y90Q>P6|c2)^7w$_jW(X^FSjS01& zO9R)+Z>l*OM?G#`dITaPnmupLoL39fv9$uD^V{<}hvxNAOZf`iiLR$0wR((XnrzK! zcE;^GCO+w;e~QJ`l}g1@>=%`f9H+^2##XZnBWm6arO{Ax(=%#kQ8rh$^YDhOSJ?DK zS`m4Ru_6=LT1At@ulK^v+#oslh=dIu>dPAL!Naf^XqyLI9#Va4nUd)aXRJ~otDV+m zW*aI;$$r^}%*&u<*+sjc=F15xM$q3_izQi**A(PoL|{sthl+KEW2`H$`qM9#T|U{?n{*dBsTxK`w>2g}NtvcraIP4w z7{s?cbROZPT6jTx&sKc0D!aMNMgKu2p_K<)sJ}&C(*Q@_$j-=1*co~6QX?v_BxmFu zM5_tD*We=MyjOrotGtXUlQ;V77^lW0XS+GdUw9djyV&*+O}}y`Fvb5`XN`v&FNaIS zlKMwDN{et*#P6f!A%xVgS*QO7B}!QfZ{jV^-sTga*$t`6ayX_vH zi?`pwo_LG@4)(>H0(a2;8`pdebTfkoTBzNMdhEa!wDGf{9nw`Ceu;t04wihAMED$; zq@uhkNeDotw7j+Lys9s9O>V7;;1Q1U@%+jRPBW4$X813+oZu+q55#}Ro?rOl4ZXwJ zPZ>Yp?njV*t%`B?M&r(^#-}jr8eeBfGN_*TG8%rymbRbJ@BoR)=)rq9{5Q9=Z^wPS z*v97%^!o4+$L?Z4Iw>>wjAML&>>c8V*Ad5AM;UOHxgN}6-U+VNkPo3HCU+nJRGM zP2hM!J`V136}Y-h;P?gL!X0(W5oizo2{GwghA%VeUq&!98Cd3-K3U7;W+a#ETQG!o zP;en`A?R><=>ZXdPzU8+?Z!(DFaz-Mz>F diff --git a/out/production/TestPaperGenerationSystem/TextFilePersistence.class b/out/production/TestPaperGenerationSystem/TextFilePersistence.class index 2fdc1b11c6cfe1bc52af7b807e0b76e8fa9f7bdd..e697a06366bf0e79014f8dc9cd4e1901acc20f5b 100644 GIT binary patch delta 1417 zcmZvbd2Ccw6vlsdI_-Ni^SaQ2FopmrtsTRAX9TXGd z#MD2GxS$V2QCSozC@N5C+3SLe;Eo%L3a+>dZdIZ6d(+w&hbMF1lx!?KDy}OIH zPYfRD+qoB*W$Z1%ttpdjmKXw8Rn-<$6;-w6+uUIwNGf+ZEah&4(;97Qh}1-9*SEIC z4Ab1Tc9whG&W#6fS!S`^;a*l4G8ROxj}$jVnyx9Hdt+NH+Gt2>UZ{)_m5H7D=Hg3Q z>ziV8W3ACh<9R{uXQjmh4i8do$oe0Q!D{g`8k$0^VztE@hqXLxNcF&OuT@y+5q;EQ zJ&qw1Yp!g*A=+9NX^YxyF!+mNi(($)F^9+5UgIDCMW^xvnF@YK;vY0&D)#I%cvRq_VYJClp*dWYaCMV9S(|ua3I(z9M zz!g;R49{Y#Mm^8*JeE%C8Dt`_l6}08px48Tyd?78p!V~!2o|u60|NU+WC;i5C5z6@ zyrSI{UR9xi#=Okel=-@QBy;|RH?;0o#Wy)5&&S*H-{D=aVTGxxk*f7QZcWx)v%u}n z8XwONhca)=yuFJ%OPsCT6Lz||uQ2TF;2|HEck~|)2fKKrgK$Y`&~r+haL9vQ8xHl{ zVw;Zs<%OGdR3j@`O`Y!TdN%6sPfX%svUK1SX)u-HoGYEDOTQA0a)#_o;-!>wKC_rd znMz#1A`PUSa`jvx1uj(4i&VCZZNltg&XCOQ8ryqP#bKca_P)H3@+&yZ2O7dWuH-|G zXb9?dNbo&_dfTe@5g&{6@VK~sk`R2fnD1ALU%c8m$}x%ckIVxJpL#N@U=^W03N2Py zOtWY)r^vMUtdEeaF{c@;MT>Y|xkX*SC^#1R7WPnrU(!zEo#E#h zLGM**lHQG(BcnllJ@k6=Fx838 zK;{$Md8(5zw(1Y+XN;xAHeWTdNw|uAnD8;`D`F+Cv$X|+2aFP=y!A782Qwo zqh;l@a?i?AOAEzDCBqimY%^PI*RsVH+ZQvJzBi22NqaE&{`cPRU+(w+|J_`?wN%@2 zw6hDqC>gw7+mI4Xg%fji+=kl)8IvZTH>ze#?d6k3PMtbt@AsL)XmL$6 z4r}%Xn#x8`_lBnUu4?lI>V3mYPHqsgeS}+^{SiS?arXt{H%mAunReoyiuE+%GEH>o z*of7F6msBg4y%aq#A%*v*0BYhg4Ft8ORG2Jn;JAPQIq!%cgH=9w<8H#b)1f;1QUz{ zDTVWuLbqvSn~tZ=T-hSQn&36Q&}eVir{Y=CR2rETF%jE!JdYQQ!%AV%OJv|$exBM| zPeX%e+&E85izgh`umi6scvZ)1cwLZh%v1A?8S2PnHHjZ3uaD>PpZ_ky%~Zy*@(*L$0* znVOST=J5hC_Gz0el4LBk4IXF-GT+JMEW%RhbrSv+Ni}xZmW-6%#ED6TDt$?cl;%mM z=ou;EU|mSIE;i9s$uUuR{Nq8cCIci-k<&=Gm^pV zpwMVf&(#Lj1cNi%S`{fZ)};@vdj}R|!-G z8`m+An;6Qi7|i}1g2milLDXtux>!!8uSRIZ<>C|UK`JiBIPArzP-(-D&#(^)G20T6 zP^!V__#z(OHhhV%7`%=S?8ny((1iu~hGwjEF&E!bN@h4W;ya$E-~bJEU(D3}o|-=x zdor&m`jPuqTKoyWP_p1x%D>@v^TJ$K(?$mOcNvXYQzUA1W)(y$Heim!7Q?(4?yA%s zdJOk2!T^VEjbSNwE7P2gv=~-Yrn?>KTkxO-7p*$B-J!*>W)&QjwuGcp)n+PBci6Vw ztjelmH@MsBzXfaAvWwu4AS?&z{6EQ;6uReI%@QzMWdj4Xa;|dOABkaY zt-C8_1e`ULL-_hhA#UvF+8`HtABU=$hgzK-6%<8a?DSYbh;O)lF{>U4B^`R zrf1n-+>DnyP-1^$Gv4gL9P<^C_yyDBA@`>>2TL^vNs`Gki)4wNb1t92Qz6nTKK79U Wp7)df{F%F_h?5wNl1n^N2FKqL=H3ke diff --git a/src/AbstractProblemGenerator.java b/src/AbstractProblemGenerator.java index 9576e3d..d33074a 100644 --- a/src/AbstractProblemGenerator.java +++ b/src/AbstractProblemGenerator.java @@ -33,7 +33,7 @@ public abstract class AbstractProblemGenerator implements IProblemGenerator { while (newProblems.size() < count && tries < maxTries) { Equation candidate = createProblem(); - String canonicalForm = candidate.toCanonicalString(); + String canonicalForm = candidate.toString(); if (!existingProblems.contains(canonicalForm) && currentBatchSet.add(canonicalForm)) { newProblems.add(candidate); diff --git a/src/Equation.java b/src/Equation.java index 76fcd70..8899a51 100644 --- a/src/Equation.java +++ b/src/Equation.java @@ -51,7 +51,7 @@ public class Equation { @Override public String toString() { StringBuilder sb = new StringBuilder(); - // 使用 IntStream 来优雅地处理操作数和操作符的交替拼接 + // 使用 IntStream 处理操作数和操作符的交替拼接 IntStream.range(0, operators.size()) .forEach(i -> sb.append(operands.get(i)) .append(" ") @@ -62,21 +62,4 @@ public class Equation { return sb.toString(); } - /** - * 生成用于唯一性校验的“规范化”字符串。 - * 对于简单的可交换运算 (如 "3 + 5"),操作数会排序以确保唯一性 ("3 + 5")。 - * 对于复杂或不可交换的运算,直接返回原始顺序的字符串。 - * - * @return 规范化的方程式字符串 - */ - public String toCanonicalString() { - // 简化处理:仅对两个操作数且操作符可交换的情况进行规范化 - if (operands.size() == 2 && operators.size() == 1 && operators.get(0).isCommutative()) { - List sortedOperands = operands.stream().sorted().collect(Collectors.toList()); - return sortedOperands.get(0) + " " + operators.get(0).getSymbol() + " " + sortedOperands.get(1); - } - - // 对于其他所有复杂情况,直接按原样拼接 - return toString().replace(" = ?", ""); - } } \ No newline at end of file diff --git a/src/IFileService.java b/src/IFileService.java index 5505040..13061cc 100644 --- a/src/IFileService.java +++ b/src/IFileService.java @@ -21,7 +21,7 @@ public interface IFileService { * 加载指定用户的所有历史题目记录。 * * @param user 要加载历史记录的用户 - * @return 一个包含所有历史题目规范化字符串的集合,用于高效查找 + * @return 一个包含所有历史题目字符串的集合,用于高效查找 * @throws IOException 当文件读取失败时抛出 */ Set loadAllProblemHistory(User user) throws IOException; diff --git a/src/TextFilePersistence.java b/src/TextFilePersistence.java index c93a69c..575e7e3 100644 --- a/src/TextFilePersistence.java +++ b/src/TextFilePersistence.java @@ -12,7 +12,6 @@ import java.time.format.DateTimeFormatter; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -24,9 +23,6 @@ public class TextFilePersistence implements IFileService { private static final DateTimeFormatter FILE_NAME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); - // 正则表达式用于从文件中解析出题目表达式部分(忽略题号和答案) - private static final Pattern PROBLEM_PATTERN = Pattern.compile("^\\d+\\.\\s*(.+?)\\s*="); - @Override public void saveProblems(User user, List problems) throws IOException { Path userDirectory = Paths.get(user.getStoragePath()); @@ -71,39 +67,14 @@ public class TextFilePersistence implements IFileService { try (BufferedReader reader = new BufferedReader(new FileReader(file))) { String line; while ((line = reader.readLine()) != null) { - Matcher matcher = PROBLEM_PATTERN.matcher(line.trim()); - if (matcher.find()) { - String expression = matcher.group(1).trim(); - // 将解析出的表达式转换为规范化形式 - // 这是一个简化的转换,假设表达式格式固定 - // 更健壮的实现会构建一个临时的 Equation 对象来获取其规范化字符串 - String canonicalForm = normalizeExpression(expression); - historySet.add(canonicalForm); - } + String cleanedLine = line.replaceFirst("^\\d+\\.\\s*", ""); + System.out.println(cleanedLine); + historySet.add(cleanedLine); } } } + return historySet; } - /** - * 一个简化的字符串层面规范化方法。 - * 它模拟了 Equation.toCanonicalString() 的逻辑。 - * - * @param expression 从文件中读取的表达式,例如 "5 + 3" 或 "12 * 4" - * @return 规范化后的字符串 - */ - private String normalizeExpression(String expression) { - String[] parts = expression.split(" "); - if (parts.length == 3) { - String op = parts[1]; - if (op.equals("+") || op.equals("*")) { - // 如果是可交换运算符,对操作数进行排序 - if (parts[0].compareTo(parts[2]) > 0) { - return parts[2] + " " + op + " " + parts[0]; - } - } - } - return expression; // 其他情况直接返回 - } } \ No newline at end of file From 8ee14a94cf2fa6b1b329de579b344184336b7645 Mon Sep 17 00:00:00 2001 From: Teptao <1650163832@qq.com> Date: Thu, 25 Sep 2025 20:19:28 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E9=A2=98=E7=9B=AE=E8=AF=BB=E5=8F=96=EF=BC=8C=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E7=A9=BA=E8=A1=8C=EF=BC=8C=E5=BF=BD=E7=95=A5?= =?UTF-8?q?=E9=A2=98=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Application.class | Bin 6663 -> 6651 bytes .../TestPaperGenerationSystem/Operator.class | Bin 1395 -> 1260 bytes .../SessionManager.class | Bin 2790 -> 2786 bytes .../TextFilePersistence.class | Bin 5176 -> 0 bytes src/Application.java | 4 +-- ...tFilePersistence.java => FileService.java} | 10 ++++---- src/Operator.java | 23 ++++-------------- src/SessionManager.java | 3 +-- 8 files changed, 13 insertions(+), 27 deletions(-) delete mode 100644 out/production/TestPaperGenerationSystem/TextFilePersistence.class rename src/{TextFilePersistence.java => FileService.java} (90%) diff --git a/out/production/TestPaperGenerationSystem/Application.class b/out/production/TestPaperGenerationSystem/Application.class index 50bfdb8aded7e5aab38b8a027e0feaf5d3d0c9bd..4aa1052d075cbf2f08887a043ddffc6826ca389c 100644 GIT binary patch delta 45 zcmZoS`E9&GgOQ8dEi)%IIJKxObF&qrFslH6dTNPtX;D#XUWrd?S!&MaM7CwZ09?io AbN~PV delta 57 zcmexu+-|Z#gHcF0B(C4}oHUag+oy(Va-8icJ@u zi@-%fk<|dRs70^hF=G`P#ioFFa(sDkb$)blCSVqdjp){B3Mcw73PUoBBnEkd0}pek zalRgf=5T6W_XNK-nH&~ikU2Dmum3WO?w?Xy~}K`9*R zVyu*Vz(kwafRgJc3k=Xi5`DCzWYgr7_$s?<1(?D#&rPZu;yf=|)#h5`Hn2`38`#tl zYF0Y`Yc#7Bdq(Y^qV&}(>9hA%1*}tG}gheXe+B5^6sdcJ7>e?wLFH%n$pg!|UmRTt3xbY89HXjj`7@#wqe4(J?8!5 zu<;7>JT4dg(o)IS%*BWRlgtPfppnVyspCJHH{@Ma3LYjJRSi26ncaqhPURoOx!>x^f7Sl~ zYR{2xBh`^_O#kJbg;lI|&uyvEfWkFIDUs2=jB$mj3+M`mhL_b9jw?K4dO?SG6rPQF oVTbSiin$AT(o>;49Z;^vXiA(urYy|xHJ6yw&@pEn1?9oUJrxR1pa1{> diff --git a/out/production/TestPaperGenerationSystem/SessionManager.class b/out/production/TestPaperGenerationSystem/SessionManager.class index 6edfdbf6302f8358bdc47f8aa67a5570329143c6..67f69467c7abbe2104c608d801f3b34b57537491 100644 GIT binary patch delta 35 rcmaDR`bc!cF%|*-^wbjP(xRf&yb_<(vecZ-w^%N+GNw*m!({~k1LY0( delta 39 vcmaDP`b>1gF%}Ww^wbjP(xRf&yb_<(veX>E#N5=)*H|vHGNw&l!DR&iKWh(p diff --git a/out/production/TestPaperGenerationSystem/TextFilePersistence.class b/out/production/TestPaperGenerationSystem/TextFilePersistence.class deleted file mode 100644 index e697a06366bf0e79014f8dc9cd4e1901acc20f5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5176 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 uKbL}hSK|-tSK*KN6W`O>{}(0y>^%R