Java实现格子匹配算法

前不久帮朋友做一个东西,里面涉及到一个核心算法。在一个AxB的大棋盘上,每个格子里有一个整数,现在有一个CxD的小棋盘,里面每个格子里也有一个整数。现在要求在大棋盘上找是否有和小棋盘匹配的区域,要求可以对称匹配(即小棋盘是大棋盘上相关区域的镜像也可以)。因为棋盘都不大,大的可能最多16x16,小的可能最多5x5,所以随手写了一个,现在把核心代码记录下来,以后有机会再改改。

Direction.java

package matchCore;

public enum Direction{
	East,
	West,
	South,
	North,
	EastMirror,
	WestMirror,
	SouthMirror,
	NorthMirror
}

 

PosAndDir.java

package matchCore;

public class PosAndDir {
	public Position pos;
	public Direction dir;
	
	public PosAndDir() {
		pos = new Position(0, 0);
		dir = Direction.South;
	}
	
	public PosAndDir(int x, int y, Direction d) {
		pos.x = x;
		pos.y = y;
		dir = d;
	}
}

 

Position.java

package matchCore;

public class Position {
	public int x;
	public int y;
	
	public Position(int a, int b) {
		x = a;
		y = b;
	}
	
	public boolean equal(Position pos) {
		if (x == pos.x && y == pos.y) return true;
		return false;
	}
}

以上三个类都是辅助定义类,用来定义位置和方向。

 

IntArrayMatch.java

package matchCore;

import java.util.ArrayList;
import java.util.List;

public class IntArrayMatch {
	// 找出所有匹配的位置和方向
	public List<PosAndDir> matchAll(int[][] base, int[][] conf) {
		if (base == null || conf == null) return null;
		if (base.length < 1 || conf.length < 1) return null;
		
		int xdim = conf.length;
		int ydim = conf[0].length;
		List<PosAndDir> list = new ArrayList<PosAndDir>();
		for (int i = 0; i < base.length; i++) {
			for (int j = 0; j < base[i].length; j++) {
				for (Direction dir : Direction.values()) {
					PosAndDir pd = new PosAndDir(i, j, dir);
					int[][] subarray = getSubArray(base, pd, xdim, ydim);
					if (subarray == null) continue;
					else if (subMatch(subarray, conf)) list.add(pd);
				}
			}
		}
		return list;
	}
	
	// 找出一个匹配的位置和方向
	public PosAndDir matchOne(int[][] base, int[][] conf) {
		if (base == null || conf == null) return null;
		if (base.length < 1 || conf.length < 1) return null;
		
		int xdim = conf.length;
		int ydim = conf[0].length;
		PosAndDir pd = new PosAndDir();
		for (int i = 0; i < base.length; i++) {
			for (int j = 0; j < base[i].length; j++) {
				pd.pos = new Position(i,j);
				for (Direction dir : Direction.values()) {
					pd.dir = dir;
					int[][] subarray = getSubArray(base, pd, xdim, ydim);
					if (subarray == null) continue;
					else if (subMatch(subarray, conf)) return pd;
				}
			}
		}
		return null;
	}
	
	// 获取sub中值为tag的格子所在的所有坐标,base为盘面,pd为sub的起始坐标和方向
	public List<Position> getPos(int[][] base, PosAndDir pd, int[][] sub, int tag) {
		int xdim = sub.length;
		int ydim = sub[0].length;
		List<Position> m_pos = new ArrayList<Position>();
		if (pd.dir == Direction.South) {
			if (pd.pos.x + xdim > base.length) return null;
			if (pd.pos.y + ydim > base[0].length) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y;

			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					if (sub[i][j] == tag) {
						Position pos = new Position(x0+i, y0+j);
						m_pos.add(pos);
					}
				}
			}
			return m_pos;
		} else if (pd.dir == Direction.SouthMirror) {
			if (pd.pos.x + xdim > base.length) return null;
			if (pd.pos.y + ydim > base[0].length) return null;
			int x0 = pd.pos.x + xdim - 1;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					if (sub[i][j] == tag) {
						Position pos = new Position(x0-i, y0+j);
						m_pos.add(pos);
					}
				}
			}
			return m_pos;
		} else if (pd.dir == Direction.East) {
			if (pd.pos.x - ydim < -1) return null;
			if (pd.pos.y + xdim > base[0].length) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					if (sub[i][j] == tag) { 
						Position pos = new Position(x0-j, y0+i);
						m_pos.add(pos);
					}
				}
			}
			return m_pos;
		} else if (pd.dir == Direction.EastMirror) {
			if (pd.pos.x - ydim < -1) return null;
			if (pd.pos.y + xdim > base[0].length) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y + xdim - 1;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					if (sub[i][j] == tag) {
						Position pos = new Position(x0-j, y0-i);
						m_pos.add(pos);
					}
				}
			}
			return m_pos;
		} else if (pd.dir == Direction.North) {
			if (pd.pos.x - xdim < -1) return null;
			if (pd.pos.y - ydim < -1) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					if (sub[i][j] == tag) {
						Position pos = new Position(x0-i, y0-j);
						m_pos.add(pos);
					}
				}
			}
			return m_pos;
		} else if (pd.dir == Direction.NorthMirror) {
			if (pd.pos.x - xdim < -1) return null;
			if (pd.pos.y - ydim < -1) return null;
			int x0 = pd.pos.x - xdim + 1;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					if (sub[i][j] == tag) {
						Position pos = new Position(x0+i, y0-j);
						m_pos.add(pos);
					}
				}
			}
			return m_pos;
		} else if (pd.dir == Direction.West) {
			if (pd.pos.x + ydim > base.length) return null;
			if (pd.pos.y - xdim < -1) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					if (sub[i][j] == tag) {
						Position pos = new Position(x0+j, y0-i);
						m_pos.add(pos);
					}
				}
			}
			return m_pos;
		} else if (pd.dir == Direction.WestMirror) {
			if (pd.pos.x + ydim > base.length) return null;
			if (pd.pos.y - xdim < -1) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y - xdim + 1;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					if (sub[i][j] == tag) {
						Position pos = new Position(x0+j, y0+i);
						m_pos.add(pos);
					}
				}
			}
			return m_pos;
		} else {
			
		}
		return null;
	}
	
	// 根据位置和方向pd给出base中大小为x,y的子矩阵
	private int[][] getSubArray(int[][] base, PosAndDir pd, int xdim, int ydim) {
		if (base == null || pd == null) {
			
		}
		if (xdim < 1 || ydim < 1) {
			
		}
		
		int[][] sub = new int[xdim][ydim];
		if (pd.dir == Direction.South) {
			if (pd.pos.x + xdim > base.length) return null;
			if (pd.pos.y + ydim > base[0].length) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					sub[i][j] = base[x0+i][y0+j];
				}
			}
			return sub;
		} else if (pd.dir == Direction.SouthMirror) {
			if (pd.pos.x + xdim > base.length) return null;
			if (pd.pos.y + ydim > base[0].length) return null;
			int x0 = pd.pos.x + xdim - 1;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					sub[i][j] = base[x0-i][y0+j];
				}
			}
			return sub;
		} else if (pd.dir == Direction.East) {
			if (pd.pos.x - ydim < -1) return null;
			if (pd.pos.y + xdim > base[0].length) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					sub[i][j] = base[x0-j][y0+i];
				}
			}
			return sub;
		} else if (pd.dir == Direction.EastMirror) {
			if (pd.pos.x - ydim < -1) return null;
			if (pd.pos.y + xdim > base[0].length) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y + xdim - 1;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					sub[i][j] = base[x0-j][y0-i];
				}
			}
			return sub;
		} else if (pd.dir == Direction.North) {
			if (pd.pos.x - xdim < -1) return null;
			if (pd.pos.y - ydim < -1) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					sub[i][j] = base[x0-i][y0-j];
				}
			}
			return sub;
		} else if (pd.dir == Direction.NorthMirror) {
			if (pd.pos.x - xdim < -1) return null;
			if (pd.pos.y - ydim < -1) return null;
			int x0 = pd.pos.x - xdim + 1;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					sub[i][j] = base[x0+i][y0-j];
				}
			}
			return sub;
		} else if (pd.dir == Direction.West) {
			if (pd.pos.x + ydim > base.length) return null;
			if (pd.pos.y - xdim < -1) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					sub[i][j] = base[x0+j][y0-i];
				}
			}
			return sub;
		} else if (pd.dir == Direction.WestMirror) {
			if (pd.pos.x + ydim > base.length) return null;
			if (pd.pos.y - xdim < -1) return null;
			int x0 = pd.pos.x;
			int y0 = pd.pos.y - xdim + 1;
			for (int i = 0; i < xdim; i++) {
				for (int j = 0; j < ydim; j++) {
					sub[i][j] = base[x0+j][y0+i];
				}
			}
			return sub;
		} else {
			
		}
		
		
		return null;
	}
	
	// 判断两个矩阵是否全同,全同返回true,否则返回false
	private boolean subMatch(int[][] src, int[][] des) {
		if (src == null || des == null) return false;
		if (src.length != des.length) return false;
		if (src.length < 1) return false;
		if (src[0].length != des[0].length) return false;
		
		for (int i = 0; i < src.length; i++) {
			for (int j = 0; j < src[i].length; j++) {
				if (src[i][j] != des[i][j]) return false;
			}
		}
			
		return true;
	}
}

上面这个类实现了匹配的主要功能。只需要在外面调用其public方法即可判断是否匹配,并且给出第一个匹配的区域的位置和方向。下面给出测试文件:

IntArrayMatchTest.java

package matchCore;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

public class IntArrayMatchTest {
	private IntArrayMatch m_match;
	private int[][] m_base;
	private int[][] m_conf;
	
	@Before
	public void setUp() throws Exception {
		m_match = new IntArrayMatch();
		m_base = new int[9][9];
		m_conf = new int[2][3];
		int c = 0;
		for (int j = 8; j >= 0; j--) {
			for (int i = 0; i < 9; i++) {
				c++;
				m_base[i][j] = c;
				System.out.print(m_base[i][j] + " ");
			}
			System.out.println();
		}
		
		m_conf[0][0] = 32;
		m_conf[0][1] = 33;
		m_conf[0][2] = 34;
		m_conf[1][0] = 41;
		m_conf[1][1] = 42;
		m_conf[1][2] = 43;
	}

	@Test
	public void testMatch() {
		PosAndDir pd = m_match.matchOne(m_base, m_conf);
		System.out.println("pos = (" + pd.pos.x + ", " + pd.pos.y + 
				"), dir = " + pd.dir.toString());
		assertEquals(5, 5);
	}

}

上面的单测结果为:

1 2 3 4 5 6 7 8 9 
10 11 12 13 14 15 16 17 18 
19 20 21 22 23 24 25 26 27 
28 29 30 31 32 33 34 35 36 
37 38 39 40 41 42 43 44 45 
46 47 48 49 50 51 52 53 54 
55 56 57 58 59 60 61 62 63 
64 65 66 67 68 69 70 71 72 
73 74 75 76 77 78 79 80 81 
pos = (4, 5), dir = West

 

转载于:https://my.oschina.net/propagator/blog/1845924

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值