最终效果:

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. 68.iOS设备尺寸及型号代码(iPhoneXR/XS)

    所有设备型号官网地址: https://www.theiphonewiki.com/wiki/Models iPhone: 机型 像素 比例 像素密度 屏幕尺寸 机型代码 发布日期 iPhone 2g ...

  2. oracle 大量连接导致数据库不能登录

    系统遇到过几次这种问题,一个系统申请的session数过大,导致数据库进程数满,无法连接的问题. pl sql develope 报的错误是:ORA-12170:TNS:链接超时 oracle用户登录 ...

  3. 2018.11.08 NOIP模拟 景点(倍增+矩阵快速幂优化dp)

    传送门 首先按照题意构造出转移矩阵. 然后可以矩阵快速幂求出答案. 但是直接做是O(n3qlogm)O(n^3qlogm)O(n3qlogm)的会TTT掉. 观察要求的东西发现我们只关系一行的答案. ...

  4. SPRING 集成 KAFKA 发送消息

    准备工作 1.安装kafka+zookeeper环境 2.利用命令创建好topic,创建一个topic my-topic 集成步骤 1.配置生产者 <?xml version="1.0 ...

  5. CAS 单点登录 服务器整合

    概述 现在企业内部的系统越来越多,如果各个应用都有自己的用户系统,那么用户将不得不要记住不同系统的用户名密码,因此独立的用户系统应运而生,各个系统之间通过单点登录的方式,这样内部只需要记住一个用户名和 ...

  6. 注意JDBC驱动的版本和JDK的版本是否匹配 JDBC连接Mariadb

    Java利用JDBC连接Mariadb的过程和MySQL基本一致. 但是需要注意JDBC驱动的版本和JDK的版本是否匹配: JDBC和JDK版本对应关系 JDBC版本 JDK版本 2.x 1.8 1. ...

  7. lambda表达式(c++11)

    1.概念 1)lambda表达式是一个可调用的代码单元,它由一个捕获列表.一个参数列表.一个箭头.一个返回类型.一个函数体组成: 2)可以忽略参数列表和返回类型,但必须包含捕获列表和函数体: 3)忽略 ...

  8. 【设计模式】Javascript设计模式——状态模式(行为型)

    注:这个模式是非常聪明的,很有点数学中组合的意思,现在,来看下这个模式是怎么个思想. 问题提出:假如某个操作有三种可能,分别为1,2,3,还可能是组合,比如先执行1,再执行2或者先执行2再执行3或者1 ...

  9. 20145232 韩文浩 《Java程序设计》第4周学习总结

    教材学习内容总结 · Chapter 继承与多态 继承:避免多个类间重复定义共同行为.继承可以理解为一个对象从另一个对象获取属性的过程. 所有Java的类均是由java.lang.Object类继承而 ...

  10. stm32常识

    cmsis全称Cortex Microcontroller Software Interface Standard,就是Cortex微处理器软件接口标准 stm32每组gpio有7组端口,分别是2个3 ...