helloPe 의 안 드 로 이 드 프로젝트 실전 의 연속 보기 - 실현 편 (2)
11977 단어 android
먼저 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 의 내부 클래스 를 계승 하 는 실현 도 있 습 니 다. 전체 항목 도 기본적으로 형성 되 었 습 니 다.
다시 한 번 말씀 드 리 지만 이 시리즈 의 글 을 쓰 는 이 유 는 안 드 로 이 드 프로젝트 의 경험 을 기록 하고 실전 능력 을 향상 시 키 기 위해 정 리 를 하 는 것 입 니 다. 얼마나 새로운 프로젝트 를 만 들 기 위해 서가 아니 라 많은 네티즌 들 에 게 배 웠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.