版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
PAGE1Android期末作業(yè)院系:計算機與信息工程學(xué)院班級:10級軟件技術(shù)1班姓名:學(xué)號:完成日期:2021年1月5日基于android平臺的連連看系統(tǒng)本系列文章記錄只是為了增加android項目實戰(zhàn)經(jīng)驗,將所學(xué)的知識用于相應(yīng)的項目開發(fā)當(dāng)中。首先介紹一下android中連連看項目的架構(gòu)及所用到的技術(shù)進行簡要分析,框架基本如下圖所示:本程序主要包含兩大模塊:即(1)表示層模塊;(2)后臺邏輯模塊;其中表示層模塊可以理解為游戲的UI及一些游戲輔助效果,表示層模塊中,重要的是實現(xiàn)游戲的布局地圖,項目中實現(xiàn)中,游戲的布局將使用自定義View的方式,在屏幕上貼圖實現(xiàn)。而菜單模塊及選關(guān)的dialog,只是為用戶提供一些常見的選擇,如重玩,過關(guān)繼續(xù),音效開關(guān)等等,為了有一個更好的用戶交互環(huán)境,dialog的實現(xiàn)將通過自定義dialog的方式。而游戲音效是MediaPlayer在不同的狀態(tài)場景下播放不同的游戲音效。而后臺邏輯模塊中,即時對于程序計算的實現(xiàn)與程序各種狀態(tài)的監(jiān)聽,將是整個程序運行的基礎(chǔ)。此模塊中將實現(xiàn)對于游戲剩余時間限制和游戲狀態(tài)的監(jiān)聽與處理。對于游戲剩余時間的監(jiān)聽,將開啟單獨的線程進行處理,從而不至于影響主程序邏輯的運行;游戲的狀態(tài)的監(jiān)控處理中,將會實現(xiàn)對于連通的兩個圖標的消除(即游戲界面的更新),游戲輸贏的監(jiān)聽判斷,游戲暫停與否等(暫停狀態(tài)需要同時將剩余時間暫停,而時間監(jiān)聽線程需要知道所處狀態(tài),此二者緊密聯(lián)系)。對于本程序中最重要的還是程序中核心算法模塊的實現(xiàn),在游戲中,最主要的算法是判斷兩個選中的圖標是否能夠連通,其余兩個算法也依賴于此算法而進行。下面著重介紹一下連接算法:在介紹連接算法之前,先簡單介紹一下連連看的布局算法,為了簡單起見,我們使用4*4的棋盤,假設(shè)棋子有四種:首先在程序初始化時,我們先將要加載的圖片在棋盤上按序繪制出來,注意每一種圖標我們繪制的時候需要一次性繪制兩次,這樣,才能保重繪制出來的每種圖標的個數(shù)都是偶數(shù)個。假設(shè)最初如下圖(1):圖(1)最初繪制圖(2)調(diào)換后棋盤這樣繪制后,我們進行一次遍歷,隨機的調(diào)換棋盤中的圖標(是現(xiàn)有棋盤中的圖標之間的調(diào)換,并不是更改成為其他的圖標)。經(jīng)過調(diào)換的棋盤可能如圖(2)所示這樣就完成了棋盤的初始化,當(dāng)然我們的棋盤在最外面一層中是不添加圖標的,為的是我們連線時候能夠使用最外層畫線,而不會出現(xiàn)穿過圖標畫線的情況,棋盤如下圖:在上一篇文章helloPe的android項目實戰(zhàn)之連連看—設(shè)計篇中,我們進行了對android中連連看的項目的設(shè)計,包括功能模塊的劃分以及核心算法的設(shè)計。此文章接上文對android平臺連連看程序進入實現(xiàn)階段。在此項目中,根據(jù)上文中對于功能的分析,我們將實現(xiàn)以下類(下面即是工程的文件目錄)在開發(fā)中,我們遵循由下向上的方式,也就是說,我們首先開發(fā)位于最底層的類,這種類并不依賴于其他的我們需要實現(xiàn)的類。根據(jù)上文的分析,首先我們開發(fā)在表示層模塊中的界面顯示類,首先是BoardView類,在android平臺下,采用繼承自View類的方式,看此類的代碼,代碼中盡量添加了詳細的注釋:packagenate.llk.view;/*導(dǎo)入包種種再次略去*/publicclassBoardViewextendsView{protectedstaticfinalintxCount=10;protectedstaticfinalintyCount=12;map連連看游戲棋盤,map中添加的int型在程序中的意思是index,而不是屏幕坐標!protectedint[][]map=newint[xCount][yCount];iconSize圖標大小,圖標是正方形,所以一個int變量表示即可protectedinticonSize;*iconCounts圖標的數(shù)目protectedinticonCounts=19;*icons所有的圖片protectedBitmap[]icons=newBitmap[iconCounts];*path可以連通點的路徑privatePoint[]path=null;*selected選中的圖標protectedList<Point>selected=newArrayList<Point>();*@paramcontext*@paramattrspublicBoardView(Contextcontext,AttributeSetattrs){super(context,attrs);calIconSize();Resourcesr=getResources();//載入連連看中的圖標資源loadBitmaps(1,r.getDrawable(R.drawable.fruit_01));loadBitmaps(2,r.getDrawable(R.drawable.fruit_02));loadBitmaps(3,r.getDrawable(R.drawable.fruit_03));loadBitmaps(4,r.getDrawable(R.drawable.fruit_04));loadBitmaps(5,r.getDrawable(R.drawable.fruit_05));loadBitmaps(6,r.getDrawable(R.drawable.fruit_06));loadBitmaps(7,r.getDrawable(R.drawable.fruit_07));loadBitmaps(8,r.getDrawable(R.drawable.fruit_08));loadBitmaps(9,r.getDrawable(R.drawable.fruit_09));loadBitmaps(10,r.getDrawable(R.drawable.fruit_10));loadBitmaps(11,r.getDrawable(R.drawable.fruit_11));loadBitmaps(12,r.getDrawable(R.drawable.fruit_12));loadBitmaps(13,r.getDrawable(R.drawable.fruit_13));loadBitmaps(14,r.getDrawable(R.drawable.fruit_14));loadBitmaps(15,r.getDrawable(R.drawable.fruit_15));loadBitmaps(16,r.getDrawable(R.drawable.fruit_17));loadBitmaps(17,r.getDrawable(R.drawable.fruit_18));loadBitmaps(18,r.getDrawable(R.drawable.fruit_19));privatevoidcalIconSize(){//取得屏幕的大小DisplayMetricsdm=newDisplayMetrics();((Activity)this.getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm);iconSize=dm.widthPixels/(xCount);*函數(shù)目的在于載入圖標資源,同時將一個key(特定的整數(shù)標識)與一個圖標進行綁定*@paramkey特定圖標的標識*@paramddrawable下的資源publicvoidloadBitmaps(intkey,Drawabled){Bitmapbitmap=Bitmap.createBitmap(iconSize,iconSize,Bitmap.Config.ARGB_8888);Canvascanvas=newCanvas(bitmap);d.setBounds(0,0,iconSize,iconSize);d.draw(canvas);icons[key]=bitmap;//未用0號index*View自帶的,但是在此方法中,有畫路徑(刪除聯(lián)通的兩個圖標),*繪制棋盤的所有圖標(也可理解為刷新,只要此map位置值>0)*放大第一個選中的圖標(selected.size()==1)@OverrideprotectedvoidonDraw(Canvascanvas){if(path!=null&&path.length>=2){for(inti=0;i<path.length-1;++i){Paintpaint=newPaint();paint.setColor(Color.BLUE);paint.setStrokeWidth(3);paint.setStyle(Paint.Style.STROKE);Pointp1=indexToScreen(path[i].x,path[i].y);Pointp2=indexToScreen(path[i+1].x,path[i+1].y);canvas.drawLine(p1.x+iconSize/2,p1.y+iconSize/2,p2.x+iconSize/2,p2.y+iconSize/2,paint);map[path[0].x][path[0].y]=0;map[path[path.length-1].x][path[path.length-1].y]=0;selected.clear();path=null;*繪制棋盤的所有圖標當(dāng)這個坐標內(nèi)的值大于0時繪制for(intx=1;x<xCount-1;++x){for(inty=1;y<yCount-1;++y){if(map[x][y]>0){Pointp=indexToScreen(x,y);canvas.drawBitmap(icons[map[x][y]],p.x,p.y,null);*繪制選中圖標,當(dāng)選中時圖標放大顯示//for(Pointposition:selected){if(selected.size()>0){Pointposition=selected.get(0);Pointp=indexToScreen(position.x,position.y);if(map[position.x][position.y]>=1){canvas.drawBitmap(icons[map[position.x][position.y]],null,newRect(p.x-5,p.y-5,p.x+iconSize+5,p.y+iconSize+5),null);super.onDraw(canvas);*@paramx數(shù)組中的橫坐標*@paramy數(shù)組中的縱坐標*@return將圖標在數(shù)組中的坐標轉(zhuǎn)成在屏幕上的真實坐標publicPointindexToScreen(intx,inty){returnnewPoint(x*iconSize,y*iconSize);*@paramx屏幕中的橫坐標*@paramy屏幕中的縱坐標*@return將圖標在屏幕中的坐標轉(zhuǎn)成在數(shù)組上的虛擬坐標publicPointscreenToIndex(intx,inty){intxindex=x/iconSize;intyindex=y/iconSize;if(xindex<xCount&&yindex<yCount){returnnewPoint(xindex,yindex);}else{returnnewPoint(0,0);*傳進來path數(shù)據(jù)更新顯示,也就是將能夠連接的圖標消除*@parampathpublicvoiddrawLine(Point[]path){this.path=path;this.invalidate();此類當(dāng)中,主要是實現(xiàn)了將連連看圖標資源的載入并且使之與一個特定的int型key相綁定,所以在后面的對于圖標的貼圖,我們能夠更加方便的操作。當(dāng)然此類中還需要存在一些必要的工具函數(shù),比如說screenToIndex方法等,因為我們是自定義View在屏幕上繪圖,需要用到屏幕坐標,但是同時,連連看游戲中,我們還需要知道圖標的索引(由于圖標都是等長等寬,容易實現(xiàn)屏幕坐標與index索引之間的轉(zhuǎn)換),以使方便操作。當(dāng)然,此類中最重要的還是重寫的onDraw函數(shù);此函數(shù)中首先判斷path是否為null并且是否兩個及以上的元素,我們之前定義path變量時,是將其作為保存連通路徑的工具。(path中的值也就是連通路徑我們將在連接算法實現(xiàn)時中加入)這里我們首先在onDraw函數(shù)中繪制出線條(如果連通),隨后將路徑的首尾中的map值設(shè)為0,程序中,第0行與最后一行map值始終為0,第0列與最后一列map值始終為0,map中的值0為0代表此處已經(jīng)沒有了圖標,根據(jù)前面與圖標資源的綁定值與map中的值對應(yīng),map中的值為幾則在相應(yīng)的index上貼上相應(yīng)的圖標。在onDraw函數(shù)中,還有一個功能就是將選擇的第一個圖標放大,以提醒玩家。最后繪制(貼圖),如前面所說,map值為多少就在對應(yīng)位置貼上相應(yīng)的圖標資源,有前面載入資源時可知并沒有對應(yīng)于0的圖標資源,為0時即不貼圖。為了防止代碼混亂,上面的BoardView類并沒有實現(xiàn)全部的功能,如touch事件的監(jiān)聽,連接算法的實現(xiàn),判斷是否無解等等。所以我們將BoardView類進行擴展,繼承BoardView的GameView(這樣做也使代碼不至于太混亂)。限于篇幅,我們可以先將GameView中用于監(jiān)聽剩余時間的內(nèi)部類實現(xiàn)(該類實現(xiàn)了Runnable接口):*用于更新剩余時間的線程*@authorhelloPeclassRefreshTimeimplementsRunnable{@Overridepublicvoidrun(){if(isContinue){while(leftTime>0&&!isStop){timerListener.onTimer(leftTime);leftTime--;try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();if(isStop&&leftTime>0){if(win());//setMode(WIN);elsesetMode(PAUSE);//setMode(LOSE);elseif(leftTime==0){setMode(LOSE);publicvoidstopTimer(){isStop=true;isContinue=false;publicvoidsetContinue(){isContinue=true;isStop=false;refreshTime=newRefreshTime();Threadt=newThread(refreshTime);//注意正確啟動一個實現(xiàn)Runnable接口的線程t.start();上面已經(jīng)提過,此線程用于控制游戲的時間。在此,再介紹自定義的幾個接口,publicinterfaceOnStateListener{publicvoidOnStateChanged(intStateMode);}只含有一個方法,主要對于游戲狀態(tài)的變換的監(jiān)聽,比如pause,stop等等。publicinterfaceOnTimerListener{publicvoidonTimer(intleftTime);}用于監(jiān)聽剩余時間,與上面線程不同的是,此方法中利用上面線程的leftTime的結(jié)果,主要用于更新游戲中用于提醒玩家的時間進度條。publicinterfaceOnToolsChangeListener{publicvoidonRefreshChanged(intcount);publicvoidonTipChanged(intcount);}tool即是我們的游戲中提供給玩家的兩個工具,一個是refresh一下游戲界面,即將現(xiàn)有的棋盤重新打亂(當(dāng)然,現(xiàn)有圖表數(shù)量不變),另一個是之前提過的hint的自動幫助功能,幫助玩家找到一組能夠連通的圖標。當(dāng)然,這兩種工具都有次數(shù)的限制。文接上回,之前介紹了項目的架構(gòu),進行了功能的分析,同時進行了BoardView類及時間控制類的開發(fā)及幾個幾口的介紹。這次我們將完整的實現(xiàn)游戲棋盤的繪制與touch事件的處理,以及游戲核心算法中連接算法、hint自動幫助算法與判斷是否無解算法的實現(xiàn)。這些代碼的處理都在繼承自BoardView類的GameView類中。首先在GameView類中添加實現(xiàn)本游戲主要算法的代碼,即連接算法的代碼(用于判斷給定的兩個位置的圖標能夠相連通):*本游戲的核心算法,判斷兩個連接點是否能夠連接,這里傳進來的就是我們點擊的兩個點轉(zhuǎn)化成index的值List<Point>p1Expand=newArrayList<Point>();List<Point>p2Expand=newArrayList<Point>();publicbooleanlink(Pointp1,Pointp2){if(p1.equals(p2)){returnfalse;}path.clear();if(map[p1.x][p1.y]==map[p2.x][p2.y]){if(linkDirect(p1,p2)){path.add(p1);path.add(p2);returntrue;*一個拐點的判斷Pointpx=newPoint(p1.x,p2.y);//假設(shè)第一種可能點if(map[p1.x][p2.y]==0&&linkDirect(p1,px)&&linkDirect(px,p2)){path.add(p1);path.add(px);path.add(p2);returntrue;}Pointpy=newPoint(p2.x,p1.y);//假設(shè)第二種可能點if(map[p2.x][p1.y]==0&&linkDirect(p1,py)&&linkDirect(py,p2)){//首先判斷map[p2.x][p1.y]中介點是否有圖標path.add(p1);path.add(py);path.add(p2);returntrue;*兩個折點(corner)expandX(p1,p1Expand);expandX(p2,p2Expand);for(inti=0;i<p1Expand.size();i++)for(intj=0;j<p2Expand.size();j++){if(p1Expand.get(i).x==p2Expand.get(j).x){if(linkDirect(p1Expand.get(i),p2Expand.get(j))){path.add(p1);path.add(p1Expand.get(i));path.add(p2Expand.get(j));path.add(p2);returntrue;}}}expandY(p1,p1Expand);expandY(p2,p2Expand);for(Pointexp1:p1Expand)for(Pointexp2:p2Expand){if(exp1.y==exp2.y){if(linkDirect(exp1,exp2)){path.add(p1);path.add(exp1);path.add(exp2);path.add(p2);returntrue;}}}returnfalse;//最后三種方式都不能連通,還是要returnfalse,不然在兩個同樣的圖標下卻沒有返回值!}returnfalse;}*判斷直線鏈接,無拐角,傳進來的點值是ScreenToIndex過的了,不過這里傳進來的不一定就是我們點擊的點,也可能是我們的拐角點(輔助點)*@paramp1*@paramp2publicbooleanlinkDirect(Pointp1,Pointp2){//if(map[p1.x][p1.y]==map[p2.x][p2.y]){//縱向直線if(p1.x==p2.x){inty1=Math.min(p1.y,p2.y);inty2=Math.max(p1.y,p2.y);booleanflag=true;for(inty=y1+1;y<y2;y++){//這個循環(huán)里容易漏掉兩個相鄰的情況,所以才加上上面的flag樣式if(map[p1.x][y]!=0){flag=false;break;}}if(flag){returntrue;}}//橫直線判斷if(p1.y==p2.y){intx1=Math.min(p1.x,p2.x);intx2=Math.max(p1.x,p2.x);booleanflag=true;for(intx=x1+1;x<x2;x++){if(map[x][p1.y]!=0){flag=false;break;}}if(flag){returntrue;}}}returnfalse;}publicvoidexpandX(Pointp,List<Point>list){list.clear();for(intx=p.x+1;x<xCount;x++){//注意此時可以等于xCount-1if(map[x][p.y]!=0)break;list.add(newPoint(x,p.y));}for(intx=p.x-1;x>=0;x--){if(map[x][p.y]!=0)break;list.add(newPoint(x,p.y));}}*向Y方向擴展,傳進來的點是index過的,而list是作為“返回值”需要保存的值publicvoidexpandY(Pointp,List<Point>list){list.clear();for(inty=p.y+1;y<yCount;y++){if(map[p.x][y]!=0)break;list.add(newPoint(p.x,y));}for(inty=p.y-1;y>=0;y--){if(map[p.x][y]!=0)break;list.add(newPoint(p.x,y));}}代碼中盡量添加注釋,此段代碼中實現(xiàn)了第一篇文章中進行的算法分析,其中l(wèi)ink(Pointp1,Pointp2)函數(shù)作為算法真正的完整實現(xiàn)者,算法的主邏輯有它實現(xiàn),linkDirect(Pointp1,Pointp2)函數(shù)作為一個工具函數(shù),用于判斷給定的兩個位置(注意不是兩個圖標,因為給定的位置不一定含有圖標,當(dāng)我們在判斷”一折型“和“二折型”的情況的時候即使如此)。而expandX(Pointp,List<Point>list)與expandY(Pointp,List<Point>list)兩個方法的同樣作為工具函數(shù),在判斷“二折型”情況時候?qū)褂?,也就是前面所說的“橫向掃描”與“縱橫掃描”。而對于link(Pointp1,Pointp2)函數(shù)中,我們的邏輯還是將大問題化為小問題處理。最終還是分解到調(diào)用linkDirect(Pointp1,Pointp2)函數(shù)來進行“直線型”的處理。以上即是程序的連接算法的實現(xiàn),除了程序算法邏輯的理解之外,還需注意在判斷的時候,若能夠連通,我們已經(jīng)將privateList<Point>path=newArrayList<Point>();保存連通路徑的path附上值,記得當(dāng)link函數(shù)返回true時,path中即保存了一條相通的路徑!完成了連接算法,下一步我們將依賴于連接算法的實現(xiàn),完成掃描是否當(dāng)前地圖已經(jīng)出現(xiàn)無解的情況,因為程序的地圖是隨機生成的,難免有時候會出現(xiàn)無解的情況;下面我們將實現(xiàn)判斷是否處于無解狀態(tài),實現(xiàn)函數(shù):*用于判斷是否當(dāng)前已經(jīng)無解publicbooleandie(){for(inty=1;y<yCount;y++)//表示從此行中的一個元素開始掃描(起點)for(intx=1;x<xCount;x++){//表示此行中指定列,組成掃描起點if(map[x][y]!=0){for(intj=y;j<yCount;j++){//表示正在被掃描的行if(j==y){//循環(huán)中的第一次掃描,為什么特殊?因為此時不一定從一行中的第一個元素開始掃描for(inti=x+1;i<xCount-1;i++){if(map[x][y]==map[i][j]&&link(newPoint(x,y),newPoint(i,j))){returnfalse;}}}else{for(inti=1;i<xCount-1;i++){if(map[x][y]==map[i][j]&&link(newPoint(x,y),newPoint(i,j)))returnfalse;}}}returntrue;代碼中也有相應(yīng)注釋,每一次判斷相當(dāng)于一次遍歷棋盤,同時注意,如果die()函數(shù)返回為false,這則證明link()函數(shù)返回了true!前面已經(jīng)提醒過:當(dāng)link返回true時,我們用于保存連通路徑的path對象中已經(jīng)保存了一條連通路徑的點的集合,只不過在die()函數(shù)中運行得到的是按遍歷順序而來的,并不是我們所指定的兩個始點與終點兩個圖標;所以在這兒,可以借die()的判斷,完成我們算法實現(xiàn)的第三個功能,即hint的自動幫助?*當(dāng)點擊help按鈕時候調(diào)用,會幫助玩家消除一對圖標publicvoidautoHelp(){if(help==0){//soundPlay.play(ID_SOUND_ERROR,0);return;}else{//soundPlay.play(ID_SOUND_TIP,0);help--;toolsChangedListener.onTipChanged(help);drawLine(path.toArray(newPoint[]{}));refreshHandler.sendRefresh(500);}}當(dāng)然此處需要介紹一下最后一行代碼的來歷:classRefreshHandlerextendsHandler{@OverridepublicvoidhandleMessage(Messagemsg){super.handleMessage(msg);if(msg.what==REFRESH_VIEW){GameView.this.invalidate();if(win()){setMode(WIN);isStop=true;isContinue=false;}elseif(die()){//調(diào)用一次die方法!此時如果die返回為false,即還能夠連通change();}}}publicvoidsendRefresh(intdelayTime){Messagemsg=newMessage();this.removeMessages(0);msg.what=REFRESH_VIEW;this.sendMessageDelayed(msg,delayTime);}}當(dāng)然對于是否已經(jīng)為贏了的判斷win()函數(shù)比較簡單,就是掃描棋盤,如果所有位置map值都為了0,即贏了,若不是,還未完成;這里就不貼代碼了。GameView類中還有一個職能就是初始化一張棋盤:我們初始化棋盤時,利用前面講解的初始算法技術(shù),遍歷棋盤,先將棋盤填滿,但是填滿首先還有一個規(guī)則就是每一種圖標的填入必須同時填入兩張,是為每種圖標都為偶數(shù)個而設(shè)定!介紹一下最后調(diào)用的change()函數(shù),也是出自于第一篇的棋盤初始算法,用于隨機將棋盤中的圖標打亂:隨機將現(xiàn)有的布局打亂,重新布局,map中現(xiàn)有圖標數(shù)量不變,相當(dāng)于一次refreshpublicvoidchange(){Randomrandom=newRandom();inttmp,xtmp,ytmp;for(intx=1;x<xCount-1;x++){for(inty=1;y<yCount-1;y++){xtmp=1+random.nextInt(xCount-2);ytmp=1+random.nextInt(yCount-2);tmp=map[x][y];map[x][y]=map[xtmp][ytmp];map[xtmp][ytmp]=tmp;}}if(die()){//如出現(xiàn)無解情況,即需要再次隨機重新打亂change();}}GameView類還是一個View,在此類中我們還要重寫View的onTouchEvent方法:*對于選擇的處理,如果是第一次按下,則將其加入到selected當(dāng)中,*若是第二次(selected.size()==1),則先判斷能不能連通@OverridepublicbooleanonTouchEvent(MotionEventevent){intsx=(int)event.getX();intsy=(int)event.getY();Pointp=screenToIndex(sx,sy);if(map[p.x][p.y]!=0){if(selected.size()==1){if(link(selected.get(0),p)){//能夠連通,path中的數(shù)據(jù)是在link判斷時如果返回真,方法內(nèi)部就已經(jīng)將數(shù)據(jù)添加進去selected.add(p);drawLine(path.toArray(newPoint[]{}));refreshHandler.sendRefresh(500);}else{//不能夠連通selected.clear();selected.add(p);}else{//此時的selected中的size只能等于0selected.add(p);GameView.this.invalidate();}}returnsuper.onTouchEvent(event);}方法中用到的selected是BoardView中的protectedList<Point>selected=newArrayList<Point>();代碼中對于功能及實現(xiàn)有相應(yīng)的注釋。到此我們可以提供接口startGame以供在程序的activity中調(diào)用:publicvoidstartPlay(){help=3;refresh=3;isContinue=true;isStop=false;toolsChangedListener.onRefreshChanged(refresh);toolsChangedListener.onTipChanged(help);leftTime=totalTime;initMap();refreshTime=newRefreshTime();Threadt=newThread(refreshTime);//注意正確啟動一個實現(xiàn)Runnable接口的線程類t.start();GameView.this.invalidate();}注意GameView中并沒有實現(xiàn)相關(guān)的自定義的接口,而是我們將會在程序的activity中實現(xiàn)項目中涉及的三個接口,但是,我們可以在GameView中進行注冊:publicvoidsetOnTimerListener(OnTimerListeneronTimerListener){this.timerListener=onTimerListener;}PublicvoidsetOnToolsChangedListener(OnToolsChangeListenertoolsChangeListener){this.toolsChangedListener=toolsChangeListener;}publicvoidsetOnStateChangeListener(OnStateListenerstateListener){this.stateListener=stateListener;}在程序中調(diào)用GameView相關(guān)函數(shù)進行初始化注冊。根據(jù)多態(tài)性的原理,在GameView中調(diào)用的相關(guān)接口中的函數(shù),也就是activity中實現(xiàn)的接口。
中南民族大學(xué)學(xué)生課程設(shè)計報告課程名稱:C程序設(shè)計語言選題名稱:通訊錄管理年級:專業(yè):信息管理與信息系統(tǒng)學(xué)號:姓名:指導(dǎo)教師:完成地點:管理學(xué)院綜合實驗室完成日期:1.課程設(shè)計的目的為了熟練掌握C語言的語法特點、及其數(shù)據(jù)結(jié)構(gòu),提高自身編寫程序的能力。通過課程設(shè)計實現(xiàn)理論知識與實際情況的結(jié)合,使所學(xué)知識能夠在現(xiàn)實社會中起到一定的作用,防止所編寫的程序脫離實際,讓程序可以更好的發(fā)揮作用,以便減輕實際工作中所遇到的繁瑣步驟,提高現(xiàn)實工作中的效率。此外通過課程設(shè)計提高邏輯思考能力和解決實際問題的能力。程序設(shè)計是公認的、最能直接有效地訓(xùn)練學(xué)生的創(chuàng)新思維,培養(yǎng)分析問題、解決問題能力的學(xué)科之一。其次課程設(shè)計有利于治學(xué)態(tài)度的培養(yǎng)。程序設(shè)計中,語句的語法和常量變量的定義都有嚴格的要求,有時輸了一個中文標點、打錯了一個字母,編譯就不通過,程序無法正常運行。因此,程序設(shè)計初學(xué)階段,學(xué)生經(jīng)常會犯這樣的錯誤,可能要通過幾次乃至十多次的反復(fù)修改、調(diào)試,才能成功,但這種現(xiàn)象會隨著學(xué)習(xí)的深入而慢慢改觀。這當(dāng)中就有一個嚴謹治學(xué)、一絲不茍的科學(xué)精神的培養(yǎng),又有一個不怕失敗、百折不撓品格的鍛煉。通訊錄信息管理系統(tǒng)是生活中不可缺少的部分編寫了一個通訊錄信息管理系統(tǒng)是十分必要的。本程序設(shè)計具有通訊信息的錄入,進行保存、查找、刪除等功能,操作界面簡潔美觀,易于操作。程序用了條件、循環(huán)、指針、結(jié)構(gòu)體等知識點,綜合了文件的打開和保存編寫的??蛇\用于小的管理軟件。軟件運用菜單實現(xiàn)交互式管理,用戶輕松的按鍵既可實現(xiàn)對軟件的操作,操作簡單易懂,功能豐富,可以很好的滿足的需要。通過對通訊錄管理系統(tǒng)的設(shè)計,進一步理解和掌握C語言這門課程的知識點,能夠熟練的調(diào)用各種函數(shù),把各種C語句有機的結(jié)合起來,提高自己C語言程序設(shè)計的能力,為今后解決實際問題打下良好基礎(chǔ)。2.設(shè)計方案論證2.1設(shè)計思路建立一個函數(shù),用來添加、顯示、刪除、查詢通訊錄等信息,完成通訊錄的功能。主函數(shù)可以調(diào)用六個子函數(shù),分別完成添加記錄、顯示記錄、刪除記錄、查詢記錄、退出系統(tǒng)等功能。在主函數(shù)中可以以1、2、3、4、0數(shù)字鍵分別可以執(zhí)行某個功能模塊。退出程序刪除記錄查詢記錄顯示退出程序刪除記錄查詢記錄顯示記錄添加記錄通訊錄管理系統(tǒng) 2.2程序設(shè)計2.2.1根據(jù)圖1定義數(shù)據(jù)類型建立函數(shù)typedefstruct { charscore;/*編號*/ charname[10];/*姓名*/ charnum[15];/*號碼*/ charemail[20]; /*郵箱*/ charage[8]; /*年齡*/ charadds[20]; /*住址*/ }Person;2.2.2主函數(shù)及其流程圖Y定義主函數(shù)main()和一系列的功能函數(shù),只有通過這些函數(shù)才可實現(xiàn)程序的功能。每次使用都會調(diào)用主函數(shù)。主函數(shù)主要是利用switch語句對數(shù)據(jù)進行處理,流程圖如下:Y添加記錄選擇1開始N選擇2YYYYNNNN退出系統(tǒng)查詢記錄刪除記錄顯示記錄選擇0選擇4選擇3添加記錄選擇1開始N選擇2YYYYNNNN退出系統(tǒng)查詢記錄刪除記錄顯示記錄選擇0選擇4選擇3結(jié)束結(jié)束2.2.3增加函數(shù)及其流程圖.添加通訊錄記錄流程圖:.顯示通訊錄記錄流程圖:.刪除通訊錄記錄流程圖:.查詢通訊錄記錄流程圖:2.3源程序#include<stdio.h>#include<stdlib.h>#include<string.h>typedefstruct { charscore;/*編號*/ charname[10];/*姓名*/ charnum[15];/*號碼*/ charemail[20]; /*郵箱*/ charage[8]; /*年齡*/ charadds[20]; /*住址*/ }Person;Personpe[80];intmenu_select() { charc; do{ system("cls"); printf("\t\t*****通訊錄*****\n"); printf("\t\t┌───────┐\n"); printf("\t\t│1.添加記錄│\n"); printf("\t\t│2.顯示記錄│\n"); printf("\t\t│3.刪除記錄│\n"); printf("\t\t│4.查詢記錄│\n"); printf("\t\t│0.退出程序│\n"); printf("\t\t└───────┘\n"); printf("\t\t請您選擇(0-4):"); c=getchar(); }while(c<'0'||c>'4'); return(c-'0'); }intInput(Personper[],intn){ inti=0; charsign,x[10]; while(sign!='n'&&sign!='N') { printf("\t編號:"); scanf("\t%d",&per[n+i].score); printf("\t姓名:"); scanf("\t%s",per[n+i].name); printf("\t年齡:"); scanf("\t%s",per[n+i].age); printf("\t電話號碼:"); scanf("\t%s",per[n+i].num); printf("\t通訊住址:"); scanf("\t%s",per[n+i].adds); printf("\t電子郵箱:"); scanf("\t%s",per[n+i].email); gets(x); printf("\n\t是否繼續(xù)添加?(Y/N)"); scanf("\t%c",&sign); i++; } return(n+i);}voidDisplay(Personper[],intn){ inti; printf("\n");/*格式*/ printf("編號姓名年齡電話號碼通訊地址電子郵箱\n"); printf("\n"); for(i=1;i<n+1;i++) { printf("%-5d%-8s%-6s%-13s%-15s%-15s\n",per[i-1].score,per[i-1].name,per[i-1].age,per[i-1].num,per[i-1].adds,per[i-1].email); if(i>1&&i%10==0) { printf("\t\n"); printf("\t"); system("pause"); printf("\t\n"); } } printf("\n"); system("pause");}intDelete_a_record(Personper[],intn){ chars[20]; inti=0,j; printf("\t請輸入想刪除記錄中的名字:"); scanf("%s",s); while(strcmp(per[i].name,s)!=0&&i<n)i++; if(i==n) { printf("\t通訊錄中沒有此人!\n"); return(n); } for(j=i;j<n-1;j++) { strcpy(per[j].num,per[j+1].num); strcpy(per[j].name,per[j+1].name); strcpy(per[j].age,per[j+1].age); strcpy(per[j].adds,per[j+1].adds); strcpy(per[j].email,per[j+1].email); per[j].score=per[j+1].score; } printf("\t\t\t已經(jīng)成功刪除!\n"); return(n-1);}voidQuery_a_record(Personper[],intn){ intm; printf("\t\n請選擇查詢方式:\n");printf("\t┌──────┐\n");printf("\t│1姓名│\n");printf("\t│2電話│\n");printf("\t│3地址│\n");printf("\t│4返回│\n");printf("\t└──────┘\n");printf("請選擇:");scanf("%d",&m);while(m!=1&&m!=2&&m!=3&&m!=4){ printf("輸入錯誤,請重新選擇:"); scanf("%d",&m); } if(m==1) { chars[20]; inti=0; printf("\t請輸入想查詢的姓名:"); scanf("\t%s",s); while(strcmp(per[i].name,s)!=0&&i<n)i++; if(i==n) { printf("\t通訊錄中沒有此人!\n"); return; } printf("\t此人編號:%d\n",per[i].score); printf("\t此人年齡:%s\n",per[i].age); printf("\t電話號碼:%s\n",per[i].num); printf("\t通訊地址:%s\n",per[i].adds); printf("\t電子郵箱:%s\n",per[i].email); }; if(m==2) { chars[20]; inti=0; printf("\t請輸入想查詢的電話:"); scanf("\t%s",s); while(strcmp(per[i].num,s)!=0&&i<n)i++; if(i==n) { printf("\t通訊錄中沒有此人!\n"); return; } printf("\t此人編號:%d\n",per[i].score); printf("\t此人姓名:%s\n",per[i].name); printf("\t此人年齡:%s\n",per[i].age); printf("\t通訊地址:%s\n",per[i].adds); printf("\t電子郵箱:%s\n",per[i].email); }; if(m==3) { chars[20]; inti=0; printf("\t請輸入想查詢的地址:"); scanf("\t%s",s); while(strcmp(per[i].adds,s)!=0&&i<n)i++; if(i==n) { printf("\t通訊錄中沒有此人!\n"); return; } printf("\t此人編號:%d\n",per[i].score); printf("\t此人姓名:%s\n",per[i].name); printf("\t此人年齡:%s\n",per[i].age); printf("\t電話號碼:%s\n",per[i].num); printf("\t電子郵箱:%s\n",per[i].email); };}voidChange(Personper[],intn){ chars[20]; inti=0; printf("\t請輸入想修改的記錄中的名字:"); scanf("%s",s); while(strcmp(per[i].name,s)!=0&&i<n)i++; if(i==n) { printf("\t通訊錄中沒有此人!\n"); return; } printf("\t編號:"); scanf("\t%d",&per[i].score); printf("\t姓名:"); scanf("\t%s",per[i].name); printf("\t年齡:"); scanf("\t%s",per[i].age); printf("\t電話號碼:"); scanf("\t%s",per[i].num); printf("\t通訊住址:"); scanf("\t%s",per[i].adds); printf("\t電子郵箱:"); scanf("\t%s",per[i].email); printf("\t修改成功!");}voidWritetoText(Personper[],intn){ inti=0; FILE*fp;/*定義文件指針*/ charfilename[20];/*定義文件名*/ printf("\t保存到文件\n");/*輸入文件名*/ printf("\t請輸入所保存的文件名:"); scanf("\t%s",filename); if((fp=fopen(filename,"w"))==NULL) { printf("\t無法打開文件\n"); system("pause"); return; } fprintf(fp,"******************************************通訊錄******************************************\n"); fprintf(fp,"編號姓名年齡電話號碼
溫馨提示
- 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五版建筑工程施工監(jiān)理單位招標投標合同書3篇
- 二零二五版古籍文獻儲藏室修復(fù)合同3篇
- 二零二五年度高品質(zhì)膩子施工服務(wù)供應(yīng)合同2篇
- 二零二五版導(dǎo)游人員旅游安全責(zé)任合同3篇
- 小區(qū)車子棚施工合同(2篇)
- 2025年度新能源項目財務(wù)監(jiān)督出納人員擔(dān)保合同2篇
- 二零二五版車位購置及租賃合同樣本12篇
- 2025年度欠條收藏:古董字畫修復(fù)與交易合同3篇
- 二零二五年度高新技術(shù)項目研發(fā)團隊聘用合同范本3篇
- 二零二五年餐飲服務(wù)人員勞動合同樣本12篇
- HG∕T 2058.1-2016 搪玻璃溫度計套
- 九宮數(shù)獨200題(附答案全)
- 泌尿科一科一品匯報課件
- 人員密集場所消防安全管理培訓(xùn)
- 白銅錫電鍍工藝
- 拜耳法氧化鋁生產(chǎn)工藝
- 2024年南京信息職業(yè)技術(shù)學(xué)院高職單招(英語/數(shù)學(xué)/語文)筆試歷年參考題庫含答案解析
- 部編版二年級下冊道德與法治第二單元《我們好好玩》全部教案
- 幼兒園利劍護蕾專項行動工作方案總結(jié)與展望
- 合同信息管理方案模板范文
- 2024年大唐云南發(fā)電有限公司招聘筆試參考題庫含答案解析
評論
0/150
提交評論