最终效果:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.caobotao.crazycat" > <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>

MainActivity.java

package com.example.caobotao.crazycat;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new PlayGround(this));
}
}

Dot.java

package com.example.caobotao.crazycat;

/**
* Created by caobotao on 15/11/9.
*/
public class Dot {
private int x;
private int y;
private int status;
static final int STATUS_ON = 1;//障碍的圆圈状态
static final int STATUS_OFF = 0;//可点击的圆圈状态
static final int STATUS_IN = 9;//猫所在的圆圈状态
public Dot(){}
//实例化时每个圆圈都是可点击的状态
public Dot(int x,int y){
this.x = x;
this.y = y;
status = STATUS_OFF;
} public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
} public int getStatus() {
return status;
} public void setStatus(int status) {
this.status = status;
} public void setXY(int x,int y){
this.x = x;
this.y = y;
}
}

PlayGround.java

package com.example.caobotao.crazycat;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Toast; import java.util.HashMap;
import java.util.Vector; /**
* Created by caobotao on 15/11/9.
*/
public class PlayGround extends SurfaceView implements OnTouchListener{
private static int WIDTH = 45;//圆圈宽度
private static final int ROW = 10;//每行显示的圆圈数
private static final int COL = 10;//每列显示的圆圈数
private static final int Blocks = 13;//初始化障碍的个数
private Dot matrix[][];
private Dot cat;
public PlayGround(Context context) {
super(context);
getHolder().addCallback(callback);
//声明ROW x COL的圆圈矩阵并初始化
matrix = new Dot[ROW][COL];
for (int i = 0;i < ROW;i ++){
for (int j = 0;j < ROW;j ++){
matrix[i][j] = new Dot(j,i);
}
}
initGame();
setOnTouchListener(this);
}
private void redraw(){
//初始化画板
Canvas canvas = getHolder().lockCanvas();
// Log.i("info", "222222");
//设置画板背景色
canvas.drawColor(Color.LTGRAY);
Paint p = new Paint();
p.setFlags(Paint.ANTI_ALIAS_FLAG);
//设置不同状态的圆圈的颜色,并绘制
for (int i = 0;i < ROW;i ++){
int offset = 0;
//如果为偶数行,设置半个圆圈宽度的偏移量
if (i % 2 != 0){
offset = WIDTH / 2;
}
for (int j = 0;j < COL; j ++){
Dot one = getDot(j, i);
switch (one.getStatus()){
case Dot.STATUS_OFF:
p.setColor(0xFFEEEEEE);
break;
case Dot.STATUS_ON:
p.setColor(0xFFFFAA00);
break;
case Dot.STATUS_IN:
p.setColor(0xFFFF0000);
break;
}
RectF rectF = new RectF(one.getX() * WIDTH + offset, one.getY() * WIDTH,
(one.getX() + 1) * WIDTH + offset, (one.getY() + 1) * WIDTH);;
// if(i % 2 ==0) {
// rectF = new RectF((one.getX() + 1) * WIDTH, (one.getY() + 2) * WIDTH, (one.getX() + 2) * WIDTH, (one.getY() + 2) * WIDTH);
// }
canvas.drawOval(rectF,p);
}
}
getHolder().unlockCanvasAndPost(canvas);
}
private void initGame(){
//将每个圆圈初始化为可点击状态
for (int i = 0;i < ROW;i ++){
for (int j = 0;j < ROW;j ++){
matrix[i][j].setStatus(Dot.STATUS_OFF);
}
}
//将(4,5)设置初始化为猫所在的圆圈,并将状态设置为猫所在
cat = getDot(4,5);
cat.setStatus(Dot.STATUS_IN);
//随机设置Blocks个障碍
for (int i = 0 ;i < Blocks;){
int x = (int) ((Math.random() * 1000)%COL);
int y = (int) ((Math.random() * 1000)%ROW);
if(getDot(x,y).getStatus() == Dot.STATUS_OFF){
getDot(x,y).setStatus(Dot.STATUS_ON);
i ++;
}
} }
private boolean isAtEdge(Dot dot){
//判断某个圆圈是否在边缘
if(dot.getX() * dot.getY() == 0 || dot.getX()+1 == ROW || dot.getY() + 1 == COL){
return true;
}
return false;
}
//获取某个圆圈的左起1,2,3,4,5,6方向的相邻的圆圈
private Dot neighbour(Dot dot,int dir){
int x = -1;
int y = -1;
switch (dir){
case 1:
//return getDot(dot.getX()-1,dot.getY());
x = dot.getX()-1;
y = dot.getY();
break;
case 2:
if(dot.getY() % 2 == 0){
x = dot.getX() - 1;
y = dot.getY() - 1;
}
else {
x = dot.getX();
y = dot.getY() - 1;
}
break;
case 3:
if(dot.getY() % 2 == 0){
x = dot.getX() ;
y = dot.getY() - 1;
}
else {
x = dot.getX() + 1;
y = dot.getY() - 1;
}
break;
case 4:
x = dot.getX() + 1;
y = dot.getY();
break;
case 5:
if(dot.getY() % 2 == 0){
x = dot.getX() ;
y = dot.getY() + 1;
}
else {
x = dot.getX() + 1;
y = dot.getY() + 1;
}
break;
case 6:
if(dot.getY() % 2 == 0){
x = dot.getX() - 1;
y = dot.getY() + 1;
}
else {
x = dot.getX();
y = dot.getY() + 1;
}
break;
}
if (x != -1 || y != -1){
return getDot(x,y);
}
return null;
}
//获取某个圆圈在某个方向到矩阵边缘或到障碍的距离,如果是到边缘,返回正值,如果是到障碍,返回负值
private int getDistance(Dot dot,int dir){
int distance = 0;
if (isAtEdge(dot)){
return 1;
}
Dot ori = dot;
Dot next;
while (true){
next = neighbour(ori,dir);
if (next.getStatus() == Dot.STATUS_ON){
return distance * -1;
}
if (isAtEdge(next)){
distance ++;
return distance;
}
distance ++;
ori = next;
}
}
//将猫移动到某个圆圈
private void moveTo(Dot dot){
Dot temp = new Dot();
temp = dot;
dot = cat;
cat = temp;
cat.setStatus(Dot.STATUS_IN);
dot.setStatus(Dot.STATUS_OFF);
//如果移动后猫已在矩阵边缘,则游戏失败
if (isAtEdge(cat)){
lose();
}
// getDot(cat.getX(),cat.getY()).setStatus(Dot.STATUS_OFF);
// dot.setStatus(Dot.STATUS_IN);
// cat.setXY(dot.getX(), dot.getY());
}
private Dot getDot(int x,int y){
return matrix[y][x];
}
Callback callback = new Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
redraw();
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//根据屏幕自适应每个圆圈的宽度
WIDTH = width / (COL + 1);
redraw();
} @Override
public void surfaceDestroyed(SurfaceHolder holder) { }
}; @Override
public boolean onTouch(View v, MotionEvent event) {
// Log.i("info","33333"); if (event.getAction() == MotionEvent.ACTION_UP){
// Log.i("info", "44444");
// Toast.makeText(getContext(),event.getX() + ":" + event.getY(),Toast.LENGTH_SHORT).show();
int x,y;
//获取点击点所在的列数
y = (int) (event.getY() / WIDTH);
//获取点击点所在的行数
if (y % 2 == 0){
x = (int) (event.getX() / WIDTH);
}
else {
x = (int) ((event.getX() - WIDTH/2) / WIDTH);
}
//如果点击点不在矩阵范围内,重新初始化游戏
if (x + 1 > COL || y + 1 > ROW){
initGame();
}
//否则如果点击的圆圈的状态是可点击的,就将此圆圈的状态设置为障碍,并将猫进行移动
else if (getDot(x,y).getStatus() == Dot.STATUS_OFF){
getDot(x,y).setStatus(Dot.STATUS_ON);
move();
}
redraw();
//
}
return true;
} private void move() {
//如果猫已在矩阵边缘,则游戏失败
if (isAtEdge(cat)){
lose();
return;
}
//猫可以移动的圆圈
Vector<Dot> available = new Vector<Dot>();
//猫可以移动的到矩阵边缘没有障碍的圆圈
Vector<Dot> positive = new Vector<Dot>();
HashMap<Dot,Integer> al = new HashMap<Dot,Integer>();
for (int i =1;i<7;i++){
Dot n = neighbour(cat,i);
if(n.getStatus() == Dot.STATUS_OFF){
available.add(n);
al.put(n,i);
if (getDistance(n,i) > 0){
positive.add(n);
}
}
}
//如果猫没有可以移动的圆圈,则游戏成功
if (available.size() == 0){
win();
}
//如果猫只有一个可以移动的圆圈,则移动到此圆圈
else if (available.size() == 1){
moveTo(available.get(0));
}
//否则选最优的圆圈进行移动
else{
Dot best = null;
//如果存在可以直接到达屏幕边缘的走向
if (positive.size() != 0){
System.out.println("向前进");
int min = 999;
for (int i = 0;i < positive.size();i ++){
int a = getDistance(positive.get(i), al.get(positive.get(i)));
if (a < min){
min = a;
best = positive.get(i);
}
}
}
//所有路径均有路障
else{
System.out.println("躲路障");
int max = 0;
for (int i = 0; i < available.size();i ++){
int k = getDistance(available.get(i),al.get(available.get(i)));
if (k < max){
max = k;
best = available.get(i);
}
}
} if(best != null) {
moveTo(best);
}
else{
moveTo(available.get(0));
} // Dot d = available.get(0);
// for (int i = 1;i<available.size();i++){
// if ( Math.min(available.get(i).getX(), available.get(i).getY()) < Math.min(d.getX(),d.getY()) ){
// d = available.get(i);
// }
// }
// moveTo(d);
}
}
//赢得游戏
private void win() {
Toast.makeText(getContext(),"YOU HAVE WON THE GAME!",Toast.LENGTH_SHORT).show();
}
//游戏失败
private void lose() {
Toast.makeText(getContext(),"YOU HAVE LOST THE GAME!",Toast.LENGTH_SHORT).show();
}
} 注:由于本项目只是用于简单学习交流,代码中难免会有bug出现,请自行调试修改。

作者:caobotao
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

Android实战源码--围住神经猫的更多相关文章

  1. Android项目源码分享

    http://blog.csdn.net/gao_chun/article/details/47263063 Android项目源码分享 给大家分享几个Android开发项目源码,大部分功能相信可以在 ...

  2. 45个android实例源码

    分享45个android实例源码,很好很强大http://www.apkbus.com/android-20978-1-1.html andriod闹钟源代码http://www.apkbus.com ...

  3. 分享45个android实例源码,很好很强大

    分享45个android实例源码,很好很强大 http://www.apkbus.com/android-20978-1-1.html 分享45个android实例源码,很好很强大http://www ...

  4. 将Android系统源码导入ecplise

    Android系统源码中带有个IDE的配置文件,目录为:development/ide/ 如果要用eclipse导入查看系统源码,则将development/ide/eclipse/.classpat ...

  5. Android 如何在Eclipse中查看Android API源码 及 support包源码

    当我们阅读android API开发文档时候,上面的每个类,以及类的各个方法都是已经写好的方法和控件,可是我们只是在搬来使用,不知道它的原理,它是如何被实现的.android系统是开源的,所以谷歌官方 ...

  6. Android之源码之模块编译和调试

    Android之源码之模块编译调试 (一) 进行源码模块修改进行编译的调试 1.首先是从git或者svn上拉一套完整的工程下来,然后全编一下,一般这个时间比较长,大概会得2,3个小时左右, 2,编译成 ...

  7. 关于查看Android系统源码【Written By KillerLegend】

    可能你会想下载Android系统源码,但是我不知道你会看多少系统的源码,如果你对源码只是偶尔看一次的话,推荐你在线看Android的系统源码,下面提供几种查看android系统源码的方法. 1:打开这 ...

  8. 【转】Android 如何在Eclipse中查看Android API源码 及 support包源码

    原文网址:http://blog.csdn.net/vipzjyno1/article/details/22954775 当我们阅读android API开发文档时候,上面的每个类,以及类的各个方法都 ...

  9. 将android Settings 源码 导入到 eclipse工程

    1.  新建 android 项目 拷贝源码/packages/apps/Settings到你的其它目录. 在eclipse中,新建项目,但是要从exitting source选择: 2. 导入相关的 ...

随机推荐

  1. MVVM中viewmodel的理解

    网上有人写了这段话,我也有同感,特别是第一种用法,很重要,后一种用法,我觉得是把第一种用法加入controller中了. 第一种 “view model” 是 “model for the view” ...

  2. Centos7 yum install vim 出现“could not retrieve mirrorlist”

    ps:来源 https://www.cnblogs.com/justphp/p/5959655.html 办法一:改dns解析 vim /etc/resolv.conf 添加: nameserver ...

  3. Educational Codeforces Round 54 E. Vasya and a Tree(树上差分数组)

    https://codeforces.com/contest/1076/problem/E 题意 给一棵树(n<=3e5),m(3e5)次查询,每次查询u,d,x,表示在u的子树中,给距离u&l ...

  4. Router types

    Inq-n. Flits are stored at the input of the router. Each input unit is connected to the switch by as ...

  5. java常用设计模式九:桥接模式

    一.概述 将抽象部分与它的实现部分分离,使它们都可以独立地变化.它是一种对象结构型模式.比如存在2个维度,第一个维度有一个抽象类A和对应的子类A1和A2:第二个维度有另一个接口B和对应的子类B1和B2 ...

  6. VGA的行场时序

    之前碰到接收VGA时有的电脑可以有的电脑会出现画面偏移. 先来了解下数字显示器时序(DMT) DMT视频时序有四种: (1)Positive H & Positive V Syncs 行同步为 ...

  7. css3实现切片动画

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <meta http- ...

  8. Web墨卡托坐标与WGS84坐标互转

    原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-78245-1-1.html 在WebGIS的开发中经常用到的地图投影为Web墨卡托和WGS84,故歌地图,bi ...

  9. 学习node.js的C++扩展

    本想买本书,可是太贵,了一下作者可惜没有回应,不然也会去支持一下.于是自己baidu罗.先是从这个入手 安装好环境 https://github.com/nodejs/node-gyp#install ...

  10. android-基础编程-RecyclerView

    以后android-基础编程*都是控件demo里面的,不再累赘重写.直接介绍控件使用. RecyclerView is a more advanced and flexible version of ...