helloPe 의 안 드 로 이 드 프로젝트 실전 의 연속 보기 - 실현 편 (2)

11977 단어 android
글 은 지난번 에 프로젝트 의 구 조 를 소개 했다. 기능 에 대한 분석 을 실시 하 는 동시에 BoardView 류 및 시간 제어 류 개발 과 몇 가지 소 개 를 했다.이번에 우 리 는 게임 바둑판 의 그리 기와 touch 사건 의 처리, 그리고 게임 핵심 알고리즘 에서 연결 알고리즘, hint 자동 도움말 알고리즘 과 풀이 알고리즘 이 없 는 지 판단 할 것 입 니 다.이 코드 들 의 처 리 는 모두 BoardView 류 의 GameView 류 에서 계승 된다.
먼저 GameView 클래스 에 본 게임 의 주요 알고리즘 을 실현 하 는 코드, 즉 알고리즘 을 연결 하 는 코드 (주어진 두 위 치 를 판단 하 는 아이콘 이 연 결 될 수 있 음) 를 추가 합 니 다.
/**

	 *         ,             ,                   index  

	 * @param p1

	 * @param p2

	 */

	List<Point> p1Expand = new ArrayList<Point>();

	List<Point> p2Expand = new ArrayList<Point>();

	

	public boolean link(Point p1,Point p2){

		if(p1.equals(p2)){

			return false;

		}

		path.clear();

		if(map[p1.x][p1.y] == map[p2.x][p2.y]){

			if(linkDirect(p1,p2)){

				path.add(p1);

				path.add(p2);

				return true;

			}

			/**

			 *        

			 */

			Point px = new Point(p1.x,p2.y);         //        

			if(map[p1.x][p2.y] == 0 && linkDirect(p1,px) && linkDirect(px,p2)){

				path.add(p1);

				path.add(px);

				path.add(p2);

				return true;

			}

			Point py = new Point(p2.x,p1.y);        //        

			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);

				return true;

			}

			

			/**

			 *     (corner)

			 */

			expandX(p1,p1Expand);

			expandX(p2,p2Expand);

			for(int i = 0; i < p1Expand.size(); i++)

				for(int j = 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);

							return true;

						}

					}

				}

			

			expandY(p1,p1Expand);

			expandY(p2,p2Expand);

			for(Point exp1:p1Expand)

				for(Point exp2:p2Expand){

					if(exp1.y == exp2.y){

						if(linkDirect(exp1,exp2)){

							path.add(p1);

							path.add(exp1);

							path.add(exp2);

							path.add(p2);

							return true;

						}

					}

				}

			return false;  //           ,   return false ,                 !

		}

		return false;

	}

	

	/**

	 *       ,   ,       ScreenToIndex   ,                   ,          (   )

	 * @param p1

	 * @param p2

	 */

	public boolean linkDirect(Point p1,Point p2){

		

		//if(map[p1.x][p1.y] == map[p2.x][p2.y]){

			//    

			if(p1.x == p2.x){

				int y1 = Math.min(p1.y, p2.y);

				int y2 = Math.max(p1.y, p2.y);

				boolean flag = true;

				for(int y = y1 + 1; y < y2; y++){//                ,        flag  

					if(map[p1.x][y] != 0){

						flag = false;

						break;

					}

				}

				if(flag){

					return true;

				}

			}

			//     

			if(p1.y == p2.y){

				int x1 = Math.min(p1.x, p2.x);

				int x2 = Math.max(p1.x, p2.x);

				boolean flag = true;

				for(int x = x1 + 1; x < x2; x++){

					if(map[x][p1.y] != 0){

						flag = false;

						break;

					}

				}

				if(flag){

					return true;

				}

			}

		//}

		return false;

	}

	/**

	 *  x    ,      index  

	 * @param p

	 * @param list

	 */

	public void expandX(Point p,List<Point> list){

		list.clear();

		for(int x = p.x + 1; x < xCount; x++){//        xCount -1 

			if(map[x][p.y] != 0)

				break;

			list.add(new Point(x,p.y));

		}

		for(int x = p.x -1; x >= 0; x--){

			if(map[x][p.y] != 0)

				break;

			list.add(new Point(x,p.y));

		}

	}

	/**

	 *  Y    ,      index  , list   “   ”      

	 * @param p

	 * @param list

	 */

	public void expandY(Point p,List<Point> list){

		list.clear();

		for(int y = p.y + 1; y < yCount; y ++){

			if(map[p.x][y] != 0)

				break;

			list.add(new Point(p.x,y));

		}

		for(int y = p.y -1 ; y >= 0; y--){

			if(map[p.x][y] != 0)

				break;

			list.add(new Point(p.x,y));

		}

	}


코드 에 주석 을 최대한 추가 합 니 다. 이 코드 에서 제1 편 에서 진 행 된 알고리즘 분석 을 실 현 했 습 니 다. 그 중에서 링크 (Point p1, Point p2) 함 수 는 알고리즘 의 진정한 완전한 실현 자로 서 알고리즘 의 주 논 리 는 이 루어 집 니 다.
linkDirect (Point p1, Point p2) 함 수 는 도구 함수 로 서 주어진 두 위 치 를 판단 하 는 데 사 용 됩 니 다.
"1 절 형" 과 "2 절 형" 의 경우 에 도 불구 하고) expandX (Point p, List < Point > list) 와 expandY (Point p, List < Point > list) 두 가지 방법 은 같은 도구 함수 로 사용 된다.
'2 절 형' 상황 을 판단 할 때 사용 합 니 다. 즉, 앞에서 말 한 '가로 스 캔' 과 '종횡 스 캔' 입 니 다. 링크 (Point p1, Point p2) 함수 에서 우리 의 논 리 는 큰 문 제 를 작은 문제 로 처리 합 니 다.
결국 linkDirect (Point p1, Point p2) 함수 로 분해 하여 '직선 형' 처 리 를 합 니 다.
이상 은 프로그램의 연결 알고리즘 의 실현 입 니 다. 프로그램 알고리즘 논리의 이 해 를 제외 하고 판단 할 때 연결 할 수 있다 면 저 희 는 이미
private List < Point > path = new Array List < Point > (); 연결 경로 의 path 첨부 값 을 저장 합 니 다. link 함수 가 true 로 돌아 갈 때 path 에 통 하 는 경 로 를 저장 한 것 을 기억 하 십시오! 완료 되 었 습 니 다!
연결 알고리즘 은 다음 단계 에 우 리 는 연결 알고리즘 의 실현 에 의존 하여 현재 지도 가 이미 풀 리 지 않 는 상황 이 발생 했 는 지 스 캔 을 완성 할 것 입 니 다. 프로그램의 지 도 는 무 작위 로 생 성 되 기 때문에 가끔 풀 리 지 않 는 상황 이 발생 할 수 있 습 니 다.
다음 에 우 리 는 무 해 상태 에 있 는 지 판단 하고 함 수 를 실현 할 것 이다.
	/**

	 *             

	 */

	public boolean die(){

		for(int y= 1; y < yCount; y++)              //               (  )

			for(int x = 1; x < xCount; x++){        //        ,      

				if(map[x][y] != 0){                 

					for(int j = y; j < yCount; j++){//         

						if(j == y){//         ,     ?                     

							for(int i = x + 1; i < xCount - 1; i++){

								if(map[x][y] == map[i][j] && link(new Point(x,y),new Point(i,j))){

									return false;

								}

							}

						}else{

							for(int i = 1; i < xCount -1; i++){

								if(map[x][y] == map[i][j] && link(new Point(x,y),new Point(i,j)))

									return false;

							}

						}

					}

				}

			}

		return true;

	}


코드 에 도 해당 하 는 주석 이 있 습 니 다. 매번 판단 은 바둑판 을 옮 겨 다 니 는 것 과 같 습 니 다. 또한 die () 함수 가 false 로 돌아 가면 링크 () 함수 가 true 로 돌아 간 다 는 것 을 증명 합 니 다. 앞에서 알 렸 듯 이 링크 가 true 로 돌아 갈 때 연결 경 로 를 저장 하 는 path 대상 에 연결 경로 의 점 집합 이 저장 되 어 있 습 니 다. die () 에 불과 합 니 다.함수 에서 실 행 된 것 은 옮 겨 다 니 는 순서에 따라 온 것 입 니 다. 우리 가 지정 한 두 개의 시작 점 과 종점 두 개의 아이콘 이 아 닙 니 다. 그래서 여기 서 die () 의 판단 을 빌려 우리 알고리즘 이 실현 하 는 세 번 째 기능, 즉 hint 의 자동 도움 을 완성 할 수 있 습 니 다!
/**

	 *    help      ,           

	 */

	public void autoHelp(){

		if(help == 0){

			//soundPlay.play(ID_SOUND_ERROR, 0);

			return ;

		}else{

			//soundPlay.play(ID_SOUND_TIP, 0);

			help--;

			toolsChangedListener.onTipChanged(help);

			drawLine(path.toArray(new Point[] {}));

			refreshHandler.sendRefresh(500);

		}

	}


물론 마지막 줄 코드 의 정 체 를 소개 해 야 합 니 다.
class RefreshHandler extends Handler{



		@Override

		public void handleMessage(Message msg) {

			super.handleMessage(msg);

			if(msg.what == REFRESH_VIEW){

				GameView.this.invalidate();

				if(win()){

					setMode(WIN);

					isStop = true;

					isContinue = false;

				}else if(die()){    //    die  !    die   false,      

					change();       //  die   link    ,    path         ,

				}                   //       autoHelp      !!!

			}

		}

		/**

		 * 

		 * @param delayTime

		 */

		public void sendRefresh(int delayTime){

			Message msg = new Message();

			this.removeMessages(0);

			msg.what = REFRESH_VIEW;

			this.sendMessageDelayed(msg, delayTime);

		}

	}


물론 이미 이 겼 는 지 에 대한 판단 win () 함수 가 비교적 간단 합 니 다. 바로 바둑판 을 스 캔 하 는 것 입 니 다. 모든 위치 맵 값 이 0 이면 이 깁 니 다. 그렇지 않 으 면 아직 완성 되 지 않 았 습 니 다. 여 기 는 코드 를 붙 이지 않 습 니 다.
GameView 클래스 의 또 다른 기능 은 바둑판 을 초기 화 하 는 것 입 니 다.
/**

	 *      

	 */

	public void initMap(){

		int x = 1;

		int y = 0;

		for(int i = 1; i < xCount -1; i++)

			for(int j =1; j < yCount -1; j++){

				map[i][j] = x;

				if(y == 1){

					x ++;

					y = 0;

					if(x == iconCounts){

						x = 1;

					}

				}else{

					y = 1;

				}

			}

		change();

		GameView.this.invalidate();

	}


우리 가 바둑판 을 초기 화 할 때 앞에서 설명 한 초기 알고리즘 기술 을 이용 하여 바둑판 을 옮 겨 다 니 며 먼저 바둑판 을 채 워 야 합 니 다. 그러나 채 워 야 할 규칙 은 먼저 모든 아이콘 의 채 워 넣 기 가 두 장 을 동시에 채 워 야 한 다 는 것 입 니 다. 모든 아이콘 이 짝수 로 설정 되 어 있 습 니 다! 마지막 으로 호출 된 change () 를 소개 합 니 다.함수 도 첫 번 째 바둑판 의 초기 알고리즘 에서 나 온 것 으로 바둑판 의 아이콘 을 무 작위 로 흐 트 러 뜨리 는 데 사 용 됩 니 다.
 /**

     *           ,    ,map         ,     refresh

     */

	public void change(){

		Random random = new Random();

		int tmp,xtmp,ytmp;

		for(int x = 1;x < xCount -1; x++){

			for(int y = 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()){              //       ,           

			change();

		}

	}


GameView 클래스 는 View 입 니 다. 이 중에서 View 의 onTouchEvent 방법 을 다시 써 야 합 니 다.
/**

	 *        ,        ,      selected  ,

	 *      (selected.size()==1),         

	 */

	@Override

	public boolean onTouchEvent(MotionEvent event) {

		int sx = (int)event.getX();

		int sy = (int)event.getY();

		Point p = screenToIndex(sx, sy);

		if(map[p.x][p.y] != 0){

			if(selected.size() == 1){

				if(link(selected.get(0),p)){   //    ,path      link        ,              

					selected.add(p);

					drawLine(path.toArray(new Point[]{}));

					refreshHandler.sendRefresh(500);

				}else{         //     

					selected.clear();

					selected.add(p);

					GameView.this.invalidate();   //      refreshHanler.sendRefresh(int)      GameView.this.invalidate()  

					                              //                ,                        。

				}

			}else{//   selected  size    0

				selected.add(p);

				GameView.this.invalidate();

			}

		}

		return super.onTouchEvent(event);

	}


방법 에 사 용 된 selected 는 BoardView 의 proctected List < Point > selected = new Array List < Point > () 이 고 코드 에 서 는 기능 및 구현 에 대한 설명 이 있 습 니 다.
프로그램의 activity 에서 호출 할 수 있 도록 인터페이스 startGame 을 제공 할 수 있 습 니 다.
public void startPlay(){

		help = 3;

		refresh = 3;

		isContinue = true;

		isStop = false;

		toolsChangedListener.onRefreshChanged(refresh);

		toolsChangedListener.onTipChanged(help);	

		leftTime = totalTime;

		initMap();

		refreshTime = new RefreshTime();

		Thread t = new Thread(refreshTime);    //          Runnable      

		t.start();

		GameView.this.invalidate();

	}


GameView 에서 사용자 정의 인 터 페 이 스 를 실현 하지 않 고 프로그램의 activity 에서 프로젝트 와 관련 된 세 개의 인 터 페 이 스 를 실현 할 것 입 니 다. 그러나 저 희 는 GameView 에 등록 할 수 있 습 니 다.
public void setOnTimerListener(OnTimerListener onTimerListener){

		this.timerListener = onTimerListener;

	}

	public void setOnToolsChangedListener(OnToolsChangeListener toolsChangeListener){

		this.toolsChangedListener = toolsChangeListener;

	}

	public void setOnStateChangeListener(OnStateListener stateListener){

		this.stateListener = stateListener;

	}


그리고 프로그램의 activity 에서 GameView 의 관련 함 수 를 호출 하여 초기 화 등록 을 합 니 다. 이렇게 하면 다 중 원리 에 따라 GameView 에서 호출 된 관련 인터페이스 에 있 는 함수, 즉 activity 에서 실 현 된 인터페이스 에 있 는 함수 입 니 다. 이것 도 android 프로그램 에서 interface 가 등록 을 실현 하 는 방식 입 니 다.
이상 은 GameView 의 기능 과 가장 중요 한 실현 을 기본적으로 묘 사 했 습 니 다. 요약 하면 map 의 초기 화 를 실 현 했 고 touch 시간의 처리 함 수 를 재 작성 하여 프로그램의 연결 알고리즘 을 완 성 했 습 니 다. hint 자동 도움말 알고리즘, die 의 풀 리 지 않 는 판단 알고리즘, 그리고 디 스 플레이 를 업데이트 하 는 데 사용 되 는 Handler 의 내부 클래스 를 계승 하 는 실현 도 있 습 니 다. 전체 항목 도 기본적으로 형성 되 었 습 니 다.
다시 한 번 말씀 드 리 지만 이 시리즈 의 글 을 쓰 는 이 유 는 안 드 로 이 드 프로젝트 의 경험 을 기록 하고 실전 능력 을 향상 시 키 기 위해 정 리 를 하 는 것 입 니 다. 얼마나 새로운 프로젝트 를 만 들 기 위해 서가 아니 라 많은 네티즌 들 에 게 배 웠 습 니 다!

좋은 웹페이지 즐겨찾기