版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
Ⅰ摘要人工智能是一門正在迅速發(fā)展的新興的,綜合性很強的交叉科學(xué)。它與生物工程、空間技術(shù)一起被并列為二十一世界三大尖端技術(shù)。它的中心任務(wù)是研究如何使計算機去做那些過去只能靠人的智力才能做的工作。目前各發(fā)達國家都把人工智能作為重點項目,列入本國的高科技發(fā)展計劃當(dāng)中,投入巨大的人力和物力。計算機人機對弈也是其中之一。作為人智能研究的一個重要分支,計算機博弈是檢驗人工水平的一個重要方面。它的研究為人工智能帶來了很多重要的方法和理論,產(chǎn)生了廣泛的社會影響和學(xué)術(shù)影響。五子棋人機對弈是計算機博弈中的一種。研究其計算機算法,可以讓我們看到人工智能的稚形,也有助于我們?nèi)四X的開發(fā)。五子棋是我國發(fā)明的,研究它可以讓更多的外國人了解五子棋,這有助于我國優(yōu)秀文化的推廣。關(guān)鍵詞:人工智能,計算人機對弈,五子棋,算法ⅡAbstractArtificialintelligenceisarapidlydevelopingnew,integratedastrongFrontierScience.Itiswithbio-engineering,spacetechnologyhasbeenlistedas21intheworldalongwiththethreecutting-edgetechnology.Itscentraltaskistostudyhowtomakethecomputerdothatinthepasttorelyonhumanintelligencetodo.AIiscurrentlyregardedasthefocusofthedevelopedcountriesincludedinthiscar'shigh-techdevelopmentprojectsinvestedtremendoushumanandmaterialresources.
Man-machinechesscomputerisoneofthem.Asahumanstudyofanimportantbranchofintelligence,thecomputergametotestthelevelofanimportantaspectofthemanual.Itsresearchinartificialintelligencehasresultedinmanyimportantmethodsandtheoriestoproduceawiderangeofsocialimpactandacademicimpact.
Man-machinechessgameRenjuinoneofthecomputer.Tostudythecomputeralgorithm,wecanseethebeginningofartificialintelligenceshadow,butalsohelpustohumanbraindevelopment.BackgammoninventedinChina,andtheresearchitcanallowmoreforeignerstounderstandandhelptopromoteChina'straditionalculture.
Keywords:ArtificialIntelligence,Man-machineCchessComputer,Man-machineChess,AlgorithmⅢ目錄TOC\o"1-2"\h\u24733摘要 Ⅰ2055Abstract Ⅱ目錄Ⅲ緒論1需求分析22.1業(yè)務(wù)需求22.2性能需求22.3系統(tǒng)平臺需求2五子棋相關(guān)基礎(chǔ)43.1五子棋解釋43.2五子棋的基本規(guī)則43.3五子棋的常用術(shù)語5開發(fā)工具、環(huán)境及其技術(shù)74.1Java簡介74.2Java編程環(huán)境9程序設(shè)計思路與實現(xiàn)105.1程序設(shè)計思路105.2程序設(shè)計13結(jié)論33參考文獻致謝附錄第一章:緒論1.1前言電腦已經(jīng)深入到日常工作和生活的方方面面,比如文字處理、信息管理、輔助設(shè)計、圖形圖像處理、教育培訓(xùn)以及游戲娛樂等。Windows系統(tǒng)的推出使電腦從高雅的學(xué)術(shù)殿堂走入了尋常百姓家,各行各業(yè)的人們無須經(jīng)過特別的訓(xùn)練就能夠使用電腦完成許許多多復(fù)雜的工作。然而,雖然現(xiàn)在世界上已經(jīng)充滿了花樣繁多的各種軟件,但它們依然不能滿足用戶的各種特殊需要,人們還不得不開發(fā)適合自己特殊需求的軟件。Java語言作為一種面向?qū)ο蟮木幊陶Z言,具有分布式,可移植,高性能,多線程等特點。通過系統(tǒng)的學(xué)習(xí),人們就可以使用它開發(fā)出功能齊全,滿足特殊需求的應(yīng)用程序。Java語言易學(xué)易用,對學(xué)習(xí)者掌握技能,開拓思維都有很大的幫助。我作為一名學(xué)生,在系統(tǒng)的學(xué)習(xí)了Java語言之后,經(jīng)常用它搞一些小程序。這次畢業(yè)設(shè)計,正好將學(xué)過的Java語言中的各種技術(shù)綜合起來,用Jbuilder2006開發(fā)工具編寫一個小游戲,既對自己學(xué)過的技能進行一次檢驗,也能系統(tǒng)地將學(xué)過的知識復(fù)習(xí)鞏固。 隨著計算機技術(shù)的不斷發(fā)展,網(wǎng)絡(luò)技術(shù)的普及范圍越來越廣,網(wǎng)絡(luò)能夠提供的服務(wù)多樣、便捷,已經(jīng)成為人們生產(chǎn)生活中不可缺少的重要組成部分。如今網(wǎng)絡(luò)休閑游戲發(fā)展迅速,它憑借健康、方便、互動性強、益智等諸多優(yōu)點,成為大部分現(xiàn)代人休閑娛樂的首選。網(wǎng)絡(luò)五子棋游戲是使用Java語言開發(fā)的一款游戲。它使用SOCKET建立連接,多線程處理數(shù)據(jù),以及可嵌入網(wǎng)絡(luò)瀏覽器的ALET作為客戶端,這些特點使這款游戲無論是服務(wù)器還是客戶端的實現(xiàn)都相對容易。通過對該軟件的編寫,還可以鞏固我們對以上各種知識的掌握和理解。 第二章需求分析為了開發(fā)出真正滿足用戶需求量的軟件產(chǎn)品,首先必須知道用戶的需求。軟件需求中包括了多個方面來說明用戶需求。在這一章中,主要從以下幾方面來說明系統(tǒng)的需求。2.1業(yè)務(wù)需求2.1.1此系統(tǒng)使用范圍要求此系統(tǒng)為智力游戲,適合于各類游戲愛好者。由于其經(jīng)典性及其游戲的簡單性,各類人士都可以也都愛玩。人們在與電腦對戰(zhàn)享受娛樂的同時,也會體會到自己的智力也會有所提升。2.1.2功能要求該款游戲主要由一下幾個模塊組成:五子棋游戲五子棋游戲人機對弈模式人人對弈模式具有悔棋功能更換棋盤背景圖2—1五子棋功能模塊圖人機對弈模式:選擇該模式可以實現(xiàn)人與電腦之間的對弈,電腦會智能的選擇該在哪處下子,并會在每次下棋結(jié)束后判斷是否有哪方已經(jīng)獲勝,如果獲勝則結(jié)束本局游戲,并提示玩家游戲結(jié)束。人人對弈模式:選擇該模式可以實現(xiàn)人與人之間的對弈,系統(tǒng)會提示哪方先下,然后玩家之間交替的下棋,同樣系統(tǒng)會在下完每次棋后判斷是否有哪方已經(jīng)獲勝,如果獲勝則結(jié)束本局游戲,并提示玩家游戲結(jié)束?;谄骞δ埽哼@個功能也是根據(jù)游戲的實際需求而存在的,在現(xiàn)實生活中難免有失誤下錯了棋,那么就需要悔棋。此功能提供了悔棋功能,使得下棋的靈活性有所提高。玩家若想悔棋,則只需選擇悔棋按鈕便可以重新下過剛才的棋。更換棋盤背景:次功能可以根據(jù)玩家的愛好任意更換棋盤的背景顏色,由于每個人對顏色的喜好不一樣,因此這個功能也是非常必需的。也行更換一種玩家所喜歡的顏色,玩家能發(fā)揮得更好。2.2性能需求該款五子棋游戲功能雖然簡單,但最主要的還是實現(xiàn)了人人對弈模式和人機對弈兩種模式,所以從這個角度來說,該款游戲需要能很好的在兩種模式間良好的轉(zhuǎn)換。雖然系統(tǒng)不大,但要在滿足玩家的基本要求的情況下,電腦有一定的智能,能給于新手一定的幫助。2.3系統(tǒng)平臺需求編程語言:JAVA操作系統(tǒng):Windowsxp系列開發(fā)工具:Myeclipse第三章五子棋的相關(guān)基礎(chǔ)3.1五子棋解釋 引用《辭海》中所言,五子棋是“棋類游戲,棋具與圍棋相同,兩人對局,輪流下子,先將五子連成一行者為勝?!?。五子棋的名稱:日文亦有“連五子、五子連、串珠、五目、五目碰、五格、五石、五法、五聯(lián)、京棋”等多種稱謂,英文則稱之為FIR(FiveInARow的縮寫)、Gomoku(日語“五目”的羅馬拼音)、Gobang、connect5、mo-rphion。捷克語piskvorky,韓語omok、韓國人還稱之為情侶棋。3.2五子棋基本規(guī)則1.五子棋行棋時,黑棋先下第一子,由天元開始,后白棋在黑棋周圍的交叉點的落子。接著黑方再以天元中心的25個交叉點的范圍內(nèi)落盤面的第三子,之后黑白雙方相互順序子。
2.最先在棋盤線交點橫向,縱向,斜向形成已方的五個棋子連續(xù)的一方為勝。
3.出現(xiàn)禁手對方指出后將判負,其中包括兩個或兩個以上的活三,活四,長連均稱之為禁手。
4.禁手只對黑棋有效,白棋無禁手。
5.黑方禁手形成時,白方需立即指出,黑方將被判負。若白方未發(fā)現(xiàn)黑方禁手存在而繼續(xù)應(yīng)子,其后指出黑方禁手不能判黑方負。
6.黑方連五與禁手同時形成,因黑方已連成五即黑方已獲勝,故禁手規(guī)則失效。
7.在對局中,在盤上落下的子又拿起來,此動作稱為拔子,若拔子將被判為負。
8.在對局中棋子掉落在棋盤上將被判負。若推子或蹭子,以盤面第一落點為準。用手將棋子推正不算違犯規(guī)則。
9.在對局中,一方自行中止比賽如:中途退場,將被判負。
10.在對局中對方宣布認輸,本局獲勝。
11.超過比賽規(guī)定所用時間限制,將被判為負:正式比賽期間,遲到時間超過比賽容許時間將被判負。
12.如下至最終一子仍不分勝負則定為平局。
13.中盤期間雙方同意和局提議,判定為平局。 3.3五子棋常用術(shù)語1.著:也稱“步”。對局中把一個棋子按照規(guī)則放到某一交叉點,稱之為一著棋。一著是否完成有兩種規(guī)則:
(1)在執(zhí)行落子無悔規(guī)則是,以行棋者的手離開棋子為一著已完成。
(2)在執(zhí)行限時規(guī)則時,以行棋者按下棋鐘作為一著已完成。
2.PASS:五子棋中引入的英文名稱,即應(yīng)該行棋的一方主動放棄此次行棋的機會,由對方繼續(xù)行棋。
3.先手:對方必須應(yīng)答的著法,如對方形成活三必須阻止其形成活四。
4.絕對先手:相對先手而言,即形成同色連四或嵌五,對方必須應(yīng)著,就是絕對先手。絕對先手又叫“沖”。
5.VCF:(VictoryofContinusFour的縮寫)意思是利用連續(xù)沖四取勝之意。利用連續(xù)不斷的沖四或嵌五的絕對先手,制止形成連五獲得勝利的一種方法。在對局接近尾聲或排局解題中一種常見的取勝技巧。
6.追下取勝:是指白棋利用黑棋禁手取勝的戰(zhàn)術(shù)。白1沖四,迫使黑2形成“四、四”禁手(即沖四,活四禁手),這種取勝方法叫做追下取勝。
7.自由取勝:追下取勝以外的取勝方法,即未利用黑棋禁手戰(zhàn)術(shù)而取勝。
8.一子雙殺:是指對局中一方落子后出現(xiàn)兩個叫殺點即兩個獲勝點,而使對方無法防守的情形。一般是有兩個沖四活三點,白棋的雙活三,雙四均可稱為一子雙殺。
9.陽線:棋盤上可見的橫線與直線的總稱。
10.陰線:也稱“斜線”。是棋盤上不可見的斜行線。
11.“四、三”:指同時具備兩個先手,其中一個四,另一個是活三。
12.“活三”、“嵌五”、“沖四”:參見五子棋重要棋形講座。
13.禁手:對局中禁止使用的戰(zhàn)術(shù)或被判為負的行棋手段。14.開局:也稱“布局”。布局階段大體為七至十幾著之內(nèi)。種類繁多,職業(yè)連珠五子棋有二十四種開局。
15.局面:亦稱“局勢”。為對局中某一段時間內(nèi)雙方子力的配置情況。
16.優(yōu)勢:是指足以取勝的優(yōu)勢局面,其對方即為敗勢。
17.妙著:對局中走出的一步精妙的著法。既合乎邏輯又出人意料,有使局面頓時改觀的效果,對局勢的發(fā)展及對局的質(zhì)量都有重大影響。
18.好著:也稱“佳著”。對局中成功的某一步。
19.正著:對局的某一局面中的正確著法。
20.劣著:對局中,導(dǎo)致嚴重不利后果的一步錯誤著法。
21.敗著:也稱“失著”“漏著”。對局中造成局面惡化的一步嚴重錯誤著法。
22.等著:對局中具有等待性的一步著法,主要意圖是等待有利時機。
23.廢著:也稱“空著”。對局中不起作用的著法。實際上指浪費時間毫無疑義的錯著。
24.搶先:對局中利用反活三或沖四的強制手段奪取主動權(quán)的著法。
25.打譜:按照棋譜演練著法,是提高棋藝水平的重要方法之一。26.復(fù)局:也叫“復(fù)著”。對局結(jié)束又重演對局的過程。一般用以研究、比較雙方的成敗得失和著法的優(yōu)劣。第四章開發(fā)工具、環(huán)境及其技術(shù)4.1JAVA簡介JAVA技術(shù)介紹: Java技術(shù)是一門編程語言,也是一個平臺,它基于Java虛擬機技術(shù),借助這個東西建立了跨平臺的優(yōu)勢。(題外話:Java熱門的原因之一就是一個跨平臺的概念,和跨平臺類似跨瀏覽器的好處也是如此,這也是現(xiàn)在AJAX技術(shù)流行的原因之一。另外現(xiàn)在熱炒的RIA富客戶端的概念下的技術(shù)除了AJAX外還有Adobe的Flash/Flex,微軟的SilverLight,SUN的JavaFX等,個人更看好FLash/Flex,原因是Flash插件在瀏覽器端占用率很高) Java技術(shù)的重要性就不講了,從最近流行的一個統(tǒng)計數(shù)據(jù)上來說,目前世界上編程語言Java、C、VB、C++依次排名前4位,這排名本身不說明什么,至少也是工業(yè)界對編程語言使用上一個側(cè)面的反映吧。 Java編程語言與眾不同之處在于:Java程序既是編譯型的(轉(zhuǎn)換為一種稱為Java字節(jié)碼的中間語言),又是解釋型的(JVM對字節(jié)碼進行解析和運行)。編譯只進行一次,而解釋在每次運行程序時都會進行。編譯后的字節(jié)碼采用一種針對JVM優(yōu)化過的機器碼形式;解釋器是JVM的實現(xiàn)。這段是摘自網(wǎng)上的,編譯原理學(xué)的不是很好,對這門語言的背后運行機制理解到這樣了。 Java平臺是一種純軟件平臺,它有三個版本JavaSE、JavaEE、JavaME。 JavaSE(JavaPlatform,StandardEdition)這個版本以前叫做J2SE,后來版本號從1.4直接跳到5.0,其實也就是1.5,所以就叫成JavaSE5.0。目前Java開發(fā)人員使用較多的版本是5.0,當(dāng)然還有JavaSE6.0這個更新的版本。它允許開發(fā)和部署在桌面、服務(wù)器、嵌入式環(huán)境和實時環(huán)境中使用的Java應(yīng)用程序。JavaSE還包含了支持JavaWeb服務(wù)開發(fā)的類,并為JavaEE這個版本提供基礎(chǔ)。 雖說桌面應(yīng)用程序,Java一直不被看好,但也稍微提一下,負責(zé)桌面GUI開發(fā)的類庫我知道的有:JDK自帶的主要是AWT/SWING這個Java原生類庫;也可以使用IBM的SWT/JFace這個第三方類庫。開發(fā)工具我了解的有:NetBeans(最近已經(jīng)是6.0final版了,做GUI有使用VB的感覺),Eclipse(SWT/JFace這個項目其實就是做Eclipse項目時擴展出來的,所以對SWT/JFace支持的也不錯)。 JavaEE(JavaPlatform,EnterpriseEdition)這個版本以前叫做J2EE,也就是大家可能聽得比較多的,也是Java比較流行的領(lǐng)域,Java的企業(yè)級版本。JavaEE下有很多流行的開發(fā)框架,像Struts、Spring、Hibernate這種流行的所謂SSH組合等。 根據(jù)項目大小、應(yīng)用領(lǐng)域,技術(shù)平臺的選擇面還是很多的,除了JavaEE,還有.Net,LAMP組合(Linux、Apatch、MySql、PHP組合),相對來說比較新Ruby在RubyonRails的框架應(yīng)用,后兩者可能在相對來說比較輕量級的Web領(lǐng)域運用成功案例比較多,更重量的企業(yè)級潛力還有待挖掘。 JavaME(JavaPlatform,MicroEdition)這個版本以前叫做J2ME。應(yīng)用領(lǐng)域像各種移動設(shè)備和嵌入式設(shè)備,比如:手機、PDA、電視機頂盒和打印機。 JavaME不是太熟悉,不過移動設(shè)備和嵌入式設(shè)備的開發(fā)個人覺得算是比較有意思的領(lǐng)域,最近比較矚目的業(yè)界新聞有一個就是Google發(fā)布開源智能手機操作系統(tǒng)開發(fā)平臺Android,也就是前一陣子炒得很火的GPhone(原來Google出的不是手機,而是一個手機操作系統(tǒng)開發(fā)平臺)。這個平臺貌似會對JavaME有些沖擊,按照網(wǎng)上的消息,Android包括:1、高度定制的Linux操作系統(tǒng)內(nèi)核及智能手機硬件驅(qū)動支持;2、經(jīng)過Google修改過的Java虛擬機Dalvik,這里的性能比SUN的Hotspot高,支持大部分Java核心類庫;3、大量智能手機開發(fā)核心類庫;4、大量現(xiàn)成的智能手機應(yīng)用軟件;5、基于Eclipse的開發(fā)環(huán)境。也是按照網(wǎng)上的說法,JavaEE提供了統(tǒng)一的編程平臺,但不能調(diào)用操作系統(tǒng)的資源;而Android下直達操作系統(tǒng),上直達應(yīng)用軟件,如:瀏覽器、日歷、地圖等。 Java開發(fā)工具很多,個人使用的IDE有Eclipse和NetBeans。Eclispe比較流行,各種插件也多,當(dāng)然用起來也不錯;NetBeans現(xiàn)在也是越做越好了,介紹這兩個IDE主要是開源的,當(dāng)然還有其它工具如JBuilder、IntelliJ、JCreator。這些IDE各有優(yōu)勢劣勢,根據(jù)你開發(fā)的項目來選擇了。4.2JAVA編程環(huán)境:4.2.1環(huán)境變量java(TM)SEDevelopmentKits,即JDK。設(shè)置環(huán)境變量:右擊我的電腦->屬性->高級->環(huán)境變量,這時候可以看到以下的環(huán)境變量:Path:系統(tǒng)在任何路徑下都可以識別Java命令。classPath:為Java加載類(包括class,lib)的路徑,只有類在classPath中,Java命令才能識別。JAVA_HOME:Java的安裝路徑。這三個變量是必須正確設(shè)置的,否則Java命令將可能不會正常運行,具體設(shè)置如下:Path:
;C:\ProgranFiles\java\jdk1.6.0_01\binclasspath:
.;ProgranFiles\java\jdk1.6.0_01\lib\dt.jar;ProgranFiles\java\jdk1.6.0_01\lib\tools.jarJAVA_HOME:
ProgranFiles\java\jdk1.6.0_014.2.2Eclipse插件XMLBuddy:編輯xml文件;下載地址為。FatJar:打包插件,可以方便的完成各種打包任務(wù),可以包含外部的包等。Log4E:Log4j插件,提供各種與log4j相關(guān)的任務(wù),Log4j專用于為程序輸入調(diào)試信息。Lomboz:Ecilpse的一個J2EE的插件,可以將很多java應(yīng)用服務(wù)器,J2EE組件和web應(yīng)用開發(fā)集成到Eclipse中,可以幫助Java開發(fā)者使用Eclipse建立,測試和部署J2ee應(yīng)用。支持jsp編寫,包括語法著色和語法檢查:。MyEclipse:J2EE開發(fā)插件,支持jsp,EJB,數(shù)據(jù)庫操作。(6)TomcatPlugin:支持Tomcat插件。第五章程序設(shè)計思路與實現(xiàn)5.1程序設(shè)計思路 5.1.1.設(shè)計思想 1.本程序要實現(xiàn)五子棋的游戲功能,必須先有一個棋盤,所以,通過繼承JPanel,然后在JPanel上畫出一個17*17的棋盤,另外還有三個按鈕:重新開局、請黑方下子和請白方下子,提醒用戶進行相應(yīng)的操作。當(dāng)然,JPanel必須放在JFrame中,所以,又通過繼承JFrame得到一個實例。 2.對于下棋的操作,通過對JPanel增加鼠標事件監(jiān)聽器MouseListener,每次當(dāng)用戶點擊鼠標時,先取得點擊的坐標值,然后換算成對應(yīng)棋盤上(即棋盤數(shù)組)的位置(數(shù)組的下標)。 3.判斷此處是否已經(jīng)有棋子,如果有則提示玩家重新下子,否則通過java里的畫圖函數(shù)在此處畫上棋子,重新刷新輸出棋盤。 4.判斷該顏色棋子的上下左右是否滿足連續(xù)五個,是的話提醒相應(yīng)玩家獲勝,不是的話,更換玩家下棋。 5.對于玩家的更換是程序自動的,每次用戶點擊鼠標后,若本局還未結(jié)束則會變換玩家,從而畫出對應(yīng)黑方白方的棋子,直到有一方獲勝程序技術(shù)。5.1.2.程序設(shè)計分析 1.本款游戲有“游戲”和“選項”兩個選項,其中“游戲”包括開局、重新開始、結(jié)束游戲幾個選項;選項里邊則包括對弈模式、悔棋、更改背景顏色幾個選項,玩家可以根據(jù)具體需要選擇使用。2.繪制棋盤,17條橫線,17條豎線,在直線交點處下棋子(實心黑白圓形)。3.首先程序會判斷對弈模式是人機對弈還是人人對弈模式,若是人機對弈則是玩家先下,玩家是黑方,電腦是白方。若是人人對弈,則是黑方先下,黑白交替下子。4.棋盤處于鼠標監(jiān)聽狀態(tài),當(dāng)鼠標在棋盤上有點擊操作的時候,程序會獲得鼠標點擊的坐標然后換算成對應(yīng)的棋盤的位置,再判斷此處是否有棋子,假如沒有,那么在此處畫出對應(yīng)顏色的實心棋子,假如已經(jīng)有棋子了,則提示玩家此處已經(jīng)有棋子請重新下棋。5.當(dāng)選擇的是人機對弈模式的時候,輪到電腦下子時,電腦會通過算法計算每個沒有棋子的位置的重要性來選擇最重要的位置下子。6.人機對弈算法簡介:本款游戲最核心的地方就是算法,因為這是整個程序最難的模塊。算法的中心思想是:利用分數(shù)代表每個位置的重要程度,越重要的位置的分數(shù)值會越高,當(dāng)電腦下棋時會先將電腦和玩家棋型的分數(shù)分別計算一遍,然后選擇二者中分數(shù)最高的點下子。如果玩家的分數(shù)高,那么代表電腦應(yīng)該防守,如果電腦的分數(shù)高,那么代表電腦應(yīng)該進攻。具體的分數(shù)值賦值如下:分數(shù)電腦玩家活二6050半活二4035死二1010半死二1010活三950700半活三900650死三100100半死三100100活四60003500半活四50003000死四4000800半死四3600750活五2000015000半活五100003300死五2000015000半死五100003300解釋一下其中的活,半活,死,半死:活:代表幾個子是相連的,中間沒有空格,兩端都至少有一個空格。半活:代表幾個子不是相連的,幾個子中間有一個空格,兩端都至少有一個空格。死:代表幾個子是相連的,中間沒有空格,但有一端緊挨著對方的棋子或有一端正好在棋盤的邊界。半死:代表幾個子不是相連的,幾個子中間有一個空格,而且一端緊挨著對方的棋子或有一端正好在棋盤的邊界。每個位置的分數(shù)的計算方式是各個方向的分數(shù)相加,最后找出電腦棋型和玩家棋型的分數(shù)的最高的位置為電腦的下棋點下棋。7.當(dāng)任何一方有五個棋子沿著橫,豎,斜連在一起時,系統(tǒng)自動判斷贏棋,并顯示黑方或白方勝利。棋局結(jié)束后,任何一方均不能繼續(xù)操作。8.程序流程如下圖4-1:圖5-1程序流程圖5.2程序設(shè)計這個游戲程序包含兩個類:DrawPanel:棋盤類,用于繪畫棋盤及棋子。PlayerVsPC:主程序類,窗口的創(chuàng)建和整個邏輯程序代碼。類DrawPanel代碼:packageresource;importjava.awt.BasicStroke;importjava.awt.Color;importjava.awt.Graphics;importjava.awt.Graphics2D;importjava.awt.geom.Ellipse2D;importjava.awt.geom.Line2D;importjavax.swing.JPanel;publicclassDrawPanelextendsJPanel{ privateint[][]a; privateintn,m; publicDrawPanel(intk[][],intn1,intm1){ a=k; n=n1; m=m1; } publicvoidpaintComponent(Graphicsg){ super.paintComponent(g); Graphics2Dg2=(Graphics2D)g; Graphics2Dg3=(Graphics2D)g; doubleX=20; doubleY=20; doublewidth=480; doubleheight=480; doublejiange=30; //畫棋盤網(wǎng)格 for(inti=0;i<=width/jiange;i++){ g2.draw(newLine2D.Double(X+i*jiange,Y,X+i*jiange,height+Y)); g2.draw(newLine2D.Double(X,Y+i*jiange,width+X,Y+i*jiange)); } //畫中間點的標記 g3.setPaint(Color.RED); g3.draw(newLine2D.Double(254,245,254,254)); g3.draw(newLine2D.Double(245,254,254,254)); g3.draw(newLine2D.Double(267,245,267,254)); g3.draw(newLine2D.Double(267,254,275,254)); g3.draw(newLine2D.Double(245,266,254,266)); g3.draw(newLine2D.Double(254,266,254,275)); g3.draw(newLine2D.Double(266,275,266,266)); g3.draw(newLine2D.Double(266,266,275,266)); //畫旗子 for(inti=1;i<a.length-1;i++){ for(intj=1;j<a[i].length-1;j++){ Ellipse2Dcircle=newEllipse2D.Double(); circle.setFrame(j*30-25,i*30-25,28,28); if(a[i][j]==1){ g2.setPaint(Color.BLACK); g2.fill(circle); }elseif(a[i][j]==2){ g2.setPaint(Color.WHITE); g2.fill(circle); } } } //畫旗子上的標記 if(n>0&&m>0){ g2.setPaint(Color.RED); g2.setStroke(newBasicStroke(1.5f)); g2.draw(newLine2D.Double(30*m-16,30*n-16,30*m-4,30*n-4)); g2.draw(newLine2D.Double(30*m-16,30*n-4,30*m-4,30*n-16)); } } }類PlayerVsPC代碼:packageresource;importjava.awt.Color;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.awt.event.MouseAdapter;importjava.awt.event.MouseEvent;importjava.awt.Toolkit;importjava.awt.Dimension;importjavax.swing.JColorChooser;importjavax.swing.JFrame;importjavax.swing.JLabel;importjavax.swing.JMenu;importjavax.swing.JMenuBar;importjavax.swing.JMenuItem;importjavax.swing.JPanel;publicclassPlayerVsPC{ privateJFrameframe; //整個窗口 privateJMenuBarbar; //菜單欄 privateJMenuItem[][]jit;//菜單項數(shù)組 privateJMenuItem[]mode;//模式項數(shù)組 privateJMenu[]jm; //菜單 publicbooleanisBlack; //是否為黑方下子狀態(tài) privateint[][]qipan; //棋盤數(shù)組 privateintrow; //當(dāng)前行 privateintcol; //當(dāng)前列 privateintprow; privateintpcol; privateColorc=newColor(145,125,62); //棋盤背景顏色 privateDrawPanelpanel; //棋盤面板 privateJLabellabel; //棋盤上方的標簽 privateJPanelpanel0; //棋盤上方條形面板 privatebooleanisEnd; privateint[][]qixingPC; privateint[][]qixingPlayer; privatebooleanisPC=true;//記錄當(dāng)前下棋模式 privatebooleancMode=true; //記錄選擇的對弈模式 publicPlayerVsPC(){ frame=newJFrame("五子棋游戲"); bar=newJMenuBar(); jm=newJMenu[2]; jit=newJMenuItem[2][]; qipan=newint[19][19]; qixingPC=newint[17][17]; qixingPlayer=newint[17][17]; for(inti=0;i<19;i++){ for(intj=0;j<19;j++){ qipan[i][j]=0; } } for(inti=0;i<17;i++){ for(intj=0;j<17;j++){ qixingPC[i][j]=0; qixingPlayer[i][j]=0; } } label=newJLabel("人"+(isPC?"機":"人")+"對弈模式,請按開局開始游戲!"); panel0=newJPanel(); addItems(); addEventAction(); printqipan(0,0); } publicvoidaddItems(){ jm[0]=newJMenu("游戲"); jm[1]=newJMenu("選項"); jit[0]=newJMenuItem[3]; jit[0][0]=newJMenuItem("開局"); jit[0][1]=newJMenuItem("重新開始"); jit[0][2]=newJMenuItem("結(jié)束游戲"); jit[1]=newJMenuItem[3]; jit[1][0]=newJMenu("對弈模式"); mode=newJMenuItem[2]; mode[0]=newJMenuItem("人人對弈"); mode[1]=newJMenuItem("人機對弈"); jit[1][0].add(mode[0]); jit[1][0].add(mode[1]); jit[1][1]=newJMenuItem("悔棋"); jit[1][2]=newJMenuItem("背景顏色"); for(inti=0;i<jm.length;i++){ for(intj=0;j<jit[i].length;j++){ jm[i].add(jit[i][j]); } } panel0.add(label); bar.add(jm[0]); bar.add(jm[1]); frame.setJMenuBar(bar); frame.add(panel0,"North"); } //給菜單項設(shè)定事件 publicvoidaddEventAction(){ jit[0][0].addActionListener(newActionListener(){ //開局 publicvoidactionPerformed(ActionEvente){ row=prow=0;col=pcol=0; isPC=cMode; isBlack=true; isEnd=false; for(inti=0;i<19;i++){ for(intj=0;j<19;j++){ if(i==0||j==0||i==(qipan.length-1)||j==(qipan.length-1)){ qipan[i][j]=-1; }else{ qipan[i][j]=0; } } } if(isPC){ //人機對弈模式 label.setText("游戲開始,請玩家先下棋!"); }else{ //人人對弈模式 label.setText("游戲開始,請"+(isBlack?"黑":"白")+"方先下棋!"); } printqipan(row,col); addEventHandler(); } }); jit[0][1].addActionListener(newActionListener(){ //重新開始 publicvoidactionPerformed(ActionEvente){ row=prow=0;col=pcol=0; isBlack=true; isEnd=false; for(inti=0;i<19;i++){ for(intj=0;j<19;j++){ if(i==0||j==0||i==(qipan.length-1)||j==(qipan.length-1)){ qipan[i][j]=-1; }else{ qipan[i][j]=0; } } } if(isPC){ //人機對弈模式 label.setText("游戲開始,請玩家先下棋!"); }else{ //人人對弈模式 label.setText("游戲開始,請"+(isBlack?"黑":"白")+"方先下棋!"); } printqipan(row,col); addEventHandler(); } }); //給模式選項添加事件監(jiān)聽 mode[0].addActionListener(newActionListener(){ publicvoidactionPerformed(ActionEvente){ cMode=false; label.setText("已選擇人"+(cMode?"機":"人")+"對弈模式,重新開局將生效!"); } }); mode[1].addActionListener(newActionListener(){ publicvoidactionPerformed(ActionEvente){ cMode=true; label.setText("已選擇人"+(cMode?"機":"人")+"對弈模式,重新開局將生效!"); } }); jit[0][2].addActionListener(newActionListener(){ //結(jié)束游戲 publicvoidactionPerformed(ActionEvente){ label.setText("游戲結(jié)束,請按開局開始游戲!"); isEnd=true; } }); jit[1][1].addActionListener(newActionListener(){ //悔棋 publicvoidactionPerformed(ActionEvente){ if(!isPC){ huiqi(); }else{ pchuiqi(); } } }); jit[1][2].addActionListener(newActionListener(){ //背景顏色 publicvoidactionPerformed(ActionEvente){ Colorcc=JColorChooser.showDialog(frame,"棋盤背景顏色", newColor(226,189,0)); if(cc!=null){ c=cc; panel.setBackground(c); } } }); } // 監(jiān)聽鼠標事件,下棋以及判斷本盤是否結(jié)束,電腦是白方,玩家是黑方 publicvoidaddEventHandler(){ panel.addMouseListener(newMouseAdapter(){ publicvoidmousePressed(MouseEvente){ if(!isEnd){ intx=(e.getX()-5)/30; inty=(e.getY()-5)/30; if(qipan[y+1][x+1]==0){ load(x+1,y+1); }else{ label.setText("此處已經(jīng)有棋子,請重新下子!"); } } } }); } //電腦下棋 publicvoidpcLoad(){ qixing(); intcount=0; inthang=0; intlie=0; for(inti=0;i<17;i++){ for(intj=0;j<17;j++){ if(qixingPC[i][j]>count){ count=qixingPC[i][j]; hang=i+1; lie=j+1; } if(qixingPlayer[i][j]>count){ count=qixingPlayer[i][j]; hang=i+1; lie=j+1; } } } if(qipan[hang][lie]==0){ load(lie,hang); return; } } //下棋子 publicvoidload(intx,inty){ col=x; row=y; if(isBlack){ prow=row; pcol=col; qipan[row][col]=1; isBlack=false; }else{ qipan[row][col]=2; isBlack=true; } printqipan(row,col); if(panduan(row-1,col-1)){ if(isPC){ label.setText("本局結(jié)束,恭喜"+(isBlack?"電腦":"玩家")+"獲勝!"); isEnd=true; }else{ label.setText("本局結(jié)束,恭喜"+(isBlack?"黑":"白")+"方獲勝!"); isEnd=true; } }else{ if(isPC){ label.setText((isBlack?"電腦":"玩家")+"在("+ row+":"+col+")處下子,"+"現(xiàn)在"+(isBlack?"玩家":"電腦")+"下子!"); }else{ label.setText((isBlack?"白":"黑")+"方在("+ row+":"+col+")處下子,"+"現(xiàn)在"+(isBlack?"黑":"白")+"下子!"); } if(!isBlack){ if(isPC){ pcLoad(); } } } } //刷新棋盤 publicvoidprintqipan(intn,intm){ panel=newDrawPanel(qipan,n,m); panel.setBackground(c); frame.add(panel,"Center"); } //人人對弈悔棋 publicvoidhuiqi(){ if(isEnd){ label.setText("游戲已經(jīng)結(jié)束不能悔棋,請重新開局!"); return; } isBlack=!isBlack; qipan[row][col]=0; printqipan(row,col); label.setText((isBlack?"黑":"白")+"方悔棋,請重新下棋!"); } //人機對弈悔棋 publicvoidpchuiqi(){ if(isEnd){ label.setText("游戲已經(jīng)結(jié)束不能悔棋,請重新開局!"); return; } qipan[row][col]=0; qipan[prow][pcol]=0; printqipan(row,col); label.setText((isBlack?"玩家":"電腦")+"悔棋,請重新下棋!"); } //算出雙方的棋形數(shù)組 publicvoidqixing(){ for(inti=0;i<17;i++){ for(intj=0;j<17;j++){ if(qipan[i+1][j+1]==0){//說明此處沒有棋子 qixingPC[i][j]=heiheng(i,j,2)+heishu(i,j,2)+heizuoxie(i,j,2)+heiyouxie(i,j,2); qixingPlayer[i][j]=heiheng(i,j,1)+heishu(i,j,1)+heizuoxie(i,j,1)+heiyouxie(i,j,1); }else{ qixingPC[i][j]=0; qixingPlayer[i][j]=0; } } } } //算出黑子橫方向的棋型數(shù)值 publicintheiheng(inthang,intlie,intnum){ intk=0;//記錄空白處的個數(shù) intcount=1;//記錄可以形成幾連 intn=hang+1;//對應(yīng)棋盤的行 intm=lie+1;//對應(yīng)棋盤的列 booleanleft=false;//判斷左邊是否有黑子 booleanliveLeft=false;//判斷左邊是活還是死 booleanliveRight=false;//判斷右邊是活還是死 while((qipan[n][m-1]!=-1)&&(qipan[n][m-1]==num||qipan[n][m-1]==0)){ if(qipan[n][m-1]==0&&k<1){//第一個空白 if(qipan[n][m-2]!=num){ liveLeft=true; break; } k++; m--; }elseif(qipan[n][m-1]==num){//黑子 left=true; m--; }else{//第二個空白 liveLeft=true; break; } } if(!left){ k=0; m=lie+1; } while((qipan[n][m+1]!=-1)&&(qipan[n][m+1]==num||qipan[n][m+1]==0)){ intt=qipan[n][m+1]; if(m==lie){ count++; m++; continue; } if(t==0&&k<1){//第一個空白 if(qipan[n][m+2]!=num){ liveRight=true; break; } k++; m++; }elseif(t==0&&k>0){//第二個空白 liveRight=true; break; }else{//黑子 m++; count++; } } returnjieguo(liveLeft,liveRight,count,k,num); } // 算出黑子豎方向的棋型數(shù)值 publicintheishu(inthang,intlie,intnum){ intk=0;//記錄空白處的個數(shù) intcount=1;//記錄可以形成幾連 intn=hang+1;//對應(yīng)棋盤的行 intm=lie+1;//對應(yīng)棋盤的列 booleantop=false;//判斷上邊是否有黑子 booleanliveLeft=false; booleanliveRight=false; while((qipan[n-1][m]!=-1)&&(qipan[n-1][m]==num||qipan[n-1][m]==0)){ if(qipan[n-1][m]==0&&k<1){//第一個空白 if(qipan[n-2][m]!=num){ liveLeft=true; break; } k++; n--; }elseif(qipan[n-1][m]==num){//黑子 top=true; n--; }else{//第二個空白 liveLeft=true; break; } } if(!top){ k=0; n=hang+1; } while((qipan[n+1][m]!=-1)&&(qipan[n+1][m]==num||qipan[n+1][m]==0)){ intt=qipan[n+1][m]; if(n==hang){ count++; n++; continue; } if(t==0&&k<1){//第一個空白 if(qipan[n+2][m]!=num){ liveRight=true; break; } k++; n++; }elseif(t==0&&k>0){//第二個空白 liveRight=true; break; }else{//黑子 n++; count++; } } //returnjieguo(k==0,count); returnjieguo(liveLeft,liveRight,count,k,num); } // 算出黑子左斜方向的棋型數(shù)值 publicintheizuoxie(inthang,intlie,intnum){ intk=0;//記錄空白處的個數(shù) intcount=1;//記錄可以形成幾連 intn=hang+1;//對應(yīng)棋盤的行 intm=lie+1;//對應(yīng)棋盤的列 booleantop=false;//判斷上邊是否有黑子 booleanliveLeft=false; booleanliveRight=false; while((qipan[n+1][m-1]!=-1)&&(qipan[n+1][m-1]==num||qipan[n+1][m-1]==0)){ if(qipan[n+1][m-1]==0&&k<1){//第一個空白 if(qipan[n+2][m-2]!=num){ liveLeft=true; break; } k++; n++; m--; }elseif(qipan[n+1][m-1]==num){//黑子 top=true; n++; m--; }else{//第二個空白 liveLeft=true; break; } } if(!top){ k=0; n=hang+1; m=lie+1; } while((qipan[n-1][m+1]!=-1)&&(qipan[n-1][m+1]==num||qipan[n-1][m+1]==0)){ intt=qipan[n-1][m+1]; if(n==(hang+2)&&m==lie){ count++; n--; m++; continue; } if(t==0&&k<1){//第一個空白 if(qipan[n-2][m+2]!=num){ liveRight=true; break; } k++; n--; m++; }elseif(t==0&&k>0){//第二個空白 liveRight=true; break; }else{//黑子 n--; m++; count++; } } returnjieguo(liveLeft,liveRight,count,k,num); } // 算出黑子右斜方向的棋型數(shù)值 publicintheiyouxie(inthang,intlie,intnum){ intk=0;//記錄空白處的個數(shù) intcount=1;//記錄可以形成幾連 intn=hang+1;//對應(yīng)棋盤的行 intm=lie+1;//對應(yīng)棋盤的列 booleantop=false;//判斷上邊是否有黑子 booleanliveLeft=false; booleanliveRight=false; while((qipan[n-1][m-1]!=-1)&&(qipan[n-1][m-1]==num||qipan[n-1][m-1]==0)){ if(qipan[n-1][m-1]==0&&k<1){//第一個空白 if(qipan[n-2][m-2]!=num){ liveLeft=true; break; } k++; n--; m--; }elseif(qipan[n-1][m-1]==num){//黑子 top=true; n--; m--; }else{//第二個空白 liveLeft=true; break; } } if(!top){ k=0; n=hang+1; m=lie+1; } while((qipan[n+1][m+1]!=-1)&&(qipan[n+1][m+1]==num||qipan[n+1][m+1]==0)){ intt=qipan[n+1][m+1]; if(n==hang&&m==lie){ count++; n++; m++; continue; } if(t==0&&k<1){//第一個空白 if(qipan[n+2][m+2]!=num){ liveRight=true; break; } k++; n++; m++; }elseif(t==0&&k>0){//第二個空白 liveRight=true; break; }else{//黑子 n++; m++; count++; } } returnjieguo(liveLeft,liveRight,count,k,num); } publicintjieguo(booleanleft,booleanright,intcount,intk,intnum){ if(count==1){ return0; }elseif(count==2){ if(left&&right){ if(k==0){ if(num==2){ return60; }else{ return50; } }else{ if(num==2){ return40; }else{ return35; } } }elseif(!left&&!right){ return0; }else{ return10; } }elseif(count==3){ if(left&&right){ if(k==0){ if(num==2){ return950; }else{ return700; } }else{ if(num==2){ return900; }else{ return650; } } }elseif(!left&&!right){ return0; }else{ return100; } }elseif(count==4){ if(left&&right){ if(k==0){ if(num==2){ return6000; }else{ return3500; } }else{ if(num==2){ return5000; }else{ return3000; } } }elseif(!left&&!right){ return0; }else{ if(k==0){ if(num==2){ return4000; }else{ return800; } }else{ if(num==2){ return3600; }else{ return750; } } } }else{ if(k==0){ if(num==2){ return20000; }else{ return15000; } }else{ if(num==2){ return10000; }else{ return3300; } } } } publicvoidshowMe(){ frame.setSize(530,600); Toolkitkit=Toolkit.getDefaultToolkit(); DimensionscreenSize=kit.getScreenSize(); intwidth=screenSize.width; intheight=screenSize.height; intx=(int)(width-600)/2; inty=(int)(height-530)/2-50; frame.setLocation(x,y); frame.setVisible(true); frame.setResizable(false); frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE); } publicstaticvoidmain(String[]args){ newPlayerVsPC().showMe(); } publicbooleanpanduan(intn,intm){ if(heng(n,m)||shu(n,m)||zuoxie(n,m)||youxie(n,m)){ returntrue; } returnfalse; } publicbooleanheng(intn,intm){ inti=n+1,j=m+1; intcount=1; while(qipan[i][j-1]==qipan[n+1][m+1]){ j--; } while(qipan[i][j+1]==qipan[n+1][m+1]){ count++; j++; } if(count>4){ returntrue; } returnfalse; } publicbooleanshu(intn,intm){ inti=n+1,j=m+1; intcount=1; while(qipan[i-1][j]==qipan[n+1][m+1]){ i--; } while(qipan[i+1][j]==qipan[n+1][m+1]){ count++; i++; } if(count>4){ returntrue; } returnfalse; } publicbooleanyouxie(intn,intm){ inti=n+1,j=m+1; intcount=1; while(qipan[i-1][j-1]==qipan[n+1][m+1]){ i--; j--; } while(qipan[i+1][j+1]==qipan[n+1][m+1]){ count++; i++; j++; } if(count>4){ returntrue; } returnfalse; } publicbooleanzuoxie(intn,intm){ inti=n+1,j=m+1; intcount=1; while(qipan[i+1][j-1]==qipan[n+1][m+1]){ i++; j--; } while(qipan[i-1][j+1]==qipan[n+1][m+1]){ count++; i--; j++; } if(count>4){ returntrue; } returnfalse; } }基于單片機和DSP的卷繞控制器數(shù)據(jù)采集和通訊設(shè)計基于MSP430單片機的柴油發(fā)電機監(jiān)控器的設(shè)計基于CPLD/FPGA和單片機的爆速儀設(shè)計基于單片機控制的晶閘管中頻感應(yīng)電源的研制基于十六位單片機的電力設(shè)備故障在線監(jiān)測裝置的設(shè)計與算法研究基于SPCE061A單片機的語音識別系統(tǒng)的研究基于PIC單片機的生物機能實驗裝置的研究基于MotorolaMC68HC08系列單片機演示系統(tǒng)的設(shè)計與實現(xiàn)基于TCP/IP協(xié)議的單片機與INTERNET互連的設(shè)計與實現(xiàn)基于嵌入式實時操作系統(tǒng)和TCP/IP協(xié)議的單片機測控系統(tǒng)AVR8位嵌入式單片機在車載全球定位系統(tǒng)顯示終端中的應(yīng)用HYPER
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度智慧社區(qū)車位共享管理服務(wù)合同范本3篇
- 2024跨境教育服務(wù)合作合同
- 2025年度住宅小區(qū)車位租賃押金退還及違約責(zé)任合同4篇
- 2025年度校園窗簾設(shè)計與施工一體化服務(wù)合同3篇
- 2025年度物流金融承運商合作協(xié)議范本8篇
- 2025年度特種物品儲藏安全管理合同4篇
- 2025年度工業(yè)遺產(chǎn)保護與拆遷補償協(xié)議3篇
- 2025年度智慧農(nóng)業(yè)監(jiān)測系統(tǒng)采購合同4篇
- 2024版門面精裝修產(chǎn)權(quán)轉(zhuǎn)讓協(xié)議
- 2025年員工辭退后債權(quán)債務(wù)處理協(xié)議3篇
- 2024版?zhèn)€人私有房屋購買合同
- 2025年山東光明電力服務(wù)公司招聘筆試參考題庫含答案解析
- 2024爆炸物運輸安全保障協(xié)議版B版
- 《神經(jīng)發(fā)展障礙 兒童社交溝通障礙康復(fù)規(guī)范》
- 2025年中建六局二級子企業(yè)總經(jīng)理崗位公開招聘高頻重點提升(共500題)附帶答案詳解
- 2024年5月江蘇省事業(yè)單位招聘考試【綜合知識與能力素質(zhì)】真題及答案解析(管理類和其他類)
- 注漿工安全技術(shù)措施
- 《食品與食品》課件
- 2024年世界職業(yè)院校技能大賽“食品安全與質(zhì)量檢測組”參考試題庫(含答案)
- 讀書分享會《白夜行》
- 2023上海高考英語詞匯手冊單詞背誦默寫表格(復(fù)習(xí)必背)
評論
0/150
提交評論