할 일이 없어서 Lianliankan에 대한 자바 스크립트도 작성했습니다. 댓글은 비교적 완벽합니다. 배우고 싶은 친구들은 읽어보세요.
Lian Lian Kan에서 가장 어려운 부분은 아마도 마우스로 클릭한 두 지점 사이에 지나갈 수 있는 경로가 있는지 확인하는 경로 검색일 것입니다. 누군가의 재귀적 글쓰기 방식을 보고 간지러움을 느껴서 알아냈고 재귀 없이는 그리 어렵지 않다는 것을 알게 되었습니다.
경로탐색은 간단한 것부터 어려운 것까지 분석되며, 먼저 직선이 직선으로 연결될 수 있는지 분석하고, 직선 위의 두 점이 두 바퀴를 돌려 연결될 수 있는지 분석하고, 마지막으로 그렇지 않을 때의 상황을 분석한다. 직선으로.
IE6, IE8, firefox3.0.3에서 테스트되었습니다.
다음과 같이 코드 코드를 복사합니다.
<html>
<머리>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JS Lianliankan 소스 코드에 주석이 달린 완벽한 버전</title>
</head>
<스타일>
테이블{
국경 붕괴: 붕괴;
}
td{
테두리: 단색 #ccc 1px;
높이: 36px;
너비: 36px;
커서: 포인터;
}
td img{
높이: 30px;
너비: 30px;
테두리: 단색 #fff 3px;
/*
필터: 알파(불투명도=80);
-moz-불투명도: 0.8;
불투명도: 0.8;
*/
}
</style>
<스크립트>
//다음 부분은 경로 검색 알고리즘 부분으로 프리젠테이션 레이어와는 관련이 없습니다.
//전역변수
var X = 16; //총 행 수
var Y = 14; //총 열 수
var 유형 = 15;//그래픽 유형
//레이아웃 행렬
//알고리즘의 편의를 위해 행렬의 첫 번째 행, 첫 번째 열, 마지막 행, 마지막 열은 모두 자연스러운 경로인 0으로 표시됩니다.
var arr = 새로운 배열(Y);
var tbl;//레이아웃의 테이블 요소 표시
var p1 = null;//검색 경로에 사용된 첫 번째 점의 좌표
var p2 = null;//검색 경로에 사용된 두 번째 점의 좌표
var e1 = null;//첫 번째 점에 해당하는 요소
var e2 = null;//두 번째 점에 해당하는 요소
//경로 검색, 두 점이 주어졌을 때 경로 검색
//경로는 연결 가능한 지점으로 표현됩니다.
함수 getPath(p1, p2){
//검색을 시작하기 전에 p1과 p2를 정렬하여 p2가 p1의 오른쪽 아래에 최대한 가도록 합니다.
//알고리즘을 단순화할 수 있습니다.
if(p1.x>p2.x){
vart = p1;
p1 = p2;
p2 = t;
}
그렇지 않은 경우(p1.x==p2.x){
if(p1.y>p2.y){
vart = p1;
p1 = p2;
p2 = t;
}
}
//연련칸의 두 지점 사이의 위치 관계를 분석하여 각 유형을 간단한 것부터 어려운 것까지 점차적으로 분석합니다.
//첫 번째 유형, 두 점이 직선 위에 있는지, 두 점이 직선으로 연결될 수 있는지 여부
if((onlineY(p1, p2)||onlineX(p1, p2)) && hasLine(p1, p2)){
상태 = '유형 1';
반환 [p1,p2];
}
//두 번째 유형은 두 점 중 하나라도 완전히 둘러싸여 있으면 작동하지 않습니다.
if( !isEmpty({x:p1.x, y:p1.y+1}) && !isEmpty({x:p1.x, y:p1.y-1}) && !isEmpty({x:p1. x-1, y:p1.y}) && !isEmpty({x:p1.x+1, y:p1.y}) ){
상태 = '유형 2';
null을 반환;
}
if( !isEmpty({x:p2.x, y:p2.y+1}) && !isEmpty({x:p2.x, y:p2.y-1}) && !isEmpty({x:p2. x-1, y:p2.y}) && !isEmpty({x:p2.x+1, y:p2.y}) ){
상태 = '유형 2';
null을 반환;
}
//세 번째 유형, 두 점이 직선 위에 있지만 직선으로 연결할 수 없습니다.
var pt0, pt1, pt2, pt3;
//모두 x축에 있는 경우 왼쪽에서 오른쪽으로 가능한 경로를 검색합니다.
//매번 4개의 정점 pt0, pt1, pt2, pt3을 구성하고 서로 연결되어 있는지 확인
if(온라인X(p1, p2)){
for(var i=0; i<Y; i++){
if(i==p1.y){
계속하다;
}
pt0 = p1;
pt1 = {x: p1.x, y: i};
pt2 = {x: p2.x, y: i};
pt3 = p2;
//꼭지점이 비어 있지 않으면 도로가 막힌 것입니다.
if(!isEmpty(pt1) || !isEmpty(pt2)){
계속하다;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
상태 = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')' ;
[pt0, pt1, pt2, pt3]을 반환합니다.
}
}
}
//모두 y축에 있는 경우 가능한 경로를 위에서 아래로 스캔합니다.
//매번 4개의 정점 pt0, pt1, pt2, pt3을 구성하고 서로 연결되어 있는지 확인
if(온라인Y(p1, p2)){
for(var j=0; j<X; j++){
if(j==p1.x){
계속하다;
}
pt0 = p1;
pt1 = {x:j, y:p1.y};
pt2 = {x:j, y:p2.y};
pt3 = p2;
//꼭지점이 비어 있지 않으면 도로가 막힌 것입니다.
if(!isEmpty(pt1) || !isEmpty(pt2)){
계속하다;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
상태 = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')' ;
[pt0, pt1, pt2, pt3]을 반환합니다.
}
}
}
//네 번째 유형, 두 점이 직선 위에 있지 않습니다.
//가능한 경로를 수직으로 먼저 스캔
//마찬가지로 매번 4개의 정점을 구성하여 통과 가능한지 확인합니다.
for(var k=0; k<Y; k++){
pt0 = p1;
pt1 = {x:p1.x, y:k};
pt2 = {x:p2.x, y:k};
pt3 = p2;
상태 = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')' ;
//특별한 경우, pt0과 pt1이 일치하는 경우
if(같음(pt0,pt1)){
//pt2가 비어 있지 않으면 이 경로가 차단됩니다.
if(!isEmpty(pt2)){
계속하다;
}
if( hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
[pt1, pt2, pt3]을 반환합니다.
}
또 다른{
계속하다;
}
}
//특별한 경우, pt2와 pt3가 겹치는 경우
else if(같음(pt2,pt3)){
//pt1이 비어 있지 않으면 이 경로가 차단됩니다.
if(!isEmpty(pt1)){
계속하다;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) ){
[pt0, pt1, pt2]를 반환합니다.
}
또 다른{
계속하다;
}
}
//pt1과 pt2가 모두 비어 있으면 작동하지 않습니다.
if(!isEmpty(pt1) || !isEmpty(pt2)){
계속하다;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
[pt0, pt1, pt2, pt3]을 반환합니다.
}
}
//가능한 경로를 수평으로 스캔
for(var k=0; k<X; k++){
pt0 = p1;
pt1 = {x:k, y:p1.y};
pt2 = {x:k, y:p2.y};
pt3 = p2;
상태 = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')' ;
if(같음(pt0,pt1)){
if(!isEmpty(pt2)){
계속하다;
}
if( hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
[pt1, pt2, pt3]을 반환합니다.
}
}
if(같음(pt2,pt3)){
if(!isEmpty(pt1)){
계속하다;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) ){
[pt0, pt1, pt2]를 반환합니다.
}
}
if(!isEmpty(pt1) || !isEmpty(pt2)){
계속하다;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
[pt0, pt1, pt2, pt3]을 반환합니다.
}
}
//상태='type4';
null을 반환;
/************ 끝 유형 4 **************/
}
함수 같음(p1, p2){
return ((p1.x==p2.x)&&(p1.y==p2.y));
}
함수 onlineX(p1, p2){
p1.y==p2.y를 반환합니다.
}
온라인 기능Y(p1, p2){
p1.x==p2.x를 반환합니다;
}
함수 isEmpty(p){
return (arr[py][px]==0);
}
함수 hasLine(p1, p2){
if(p1.x==p2.x&&p1.y==p2.y){
사실을 반환;
}
if(온라인Y(p1, p2)){
var i = p1.y>p2.y?p2.y:p1.y;
나는 = 나는+1;
var 최대 = p1.y>p2.y?p1.y:p2.y;
for(; i<max; i++){
var p = {x: p1.x, y: i};
if(!isEmpty(p)){
부서지다
}
}
if(i==최대){
사실을 반환;
}
거짓을 반환;
}
else if(onlineX(p1, p2)){
var j = p1.x>p2.x?p2.x:p1.x;
j = j+1;
var 최대 = p1.x>p2.x?p1.x:p2.x;
for(; j<최대; j++){
var p = {x: j, y: p1.y};
if(!isEmpty(p)){
부서지다
}
}
if(j==최대){
사실을 반환;
}
거짓을 반환;
}
}
//다음 부분은 그리기, 행렬 초기화, 마우스 이벤트 바인딩 등을 포함한 프레젠테이션 계층 부분입니다.
함수 $(id){return document.getElementById(id)}
var t1, t2;//테스트용
//그림 기본 경로
var IMG_PATH = '//www.VeVB.COm';
//초기화
함수 초기화(){
//이미지 라이브러리 구축
var imgs = 새로운 배열(30);
for(var i=1; i<=30; i++){
imgs[i] = 'r_' + i + '.gif';
}
tbl = $('tbl');
//테이블 구성
for(var row=0;row<Y-2;row++){
var tr=tbl.insertRow(-1);
for(var col=0;col<X-2;col++) {
var td=tr.insertCell(-1);
}
}
//행렬 구성
for(var i=0; i<Y; i++){
arr[i] = 새로운 배열(X);
for(var j=0; j<X; j++){
arr[i][j] = 0;
}
}
var 총계 = (X-2)*(Y-2);
var tmp = new Array(total);//임의의 위치를 생성하는 데 사용됩니다.
for(var i=0; i<total; i++){
tmp[i] = 0;
}
for(var i=0; i<total; i++){
if(tmp[i]==0){
var t = Math.floor(Math.random()*types) + 1;
tmp[i] = t;
동안(참){
var c = Math.floor(Math.random()*(total-i)) + i;
if(tmp[c]==0){
tmp[c] = t;
부서지다;
}
}
}
}
var c = 0;
for(var i=1; i<Y-1; i++){
for(var j=1; j<X-1; j++){
arr[i][j] = tmp[c++];
tbl.rows[i-1].cells[j-1].innerHTML = '<img src="' + IMG_PATH + imgs[arr[i][j]] + '" />';
}
}
//마우스 이벤트 바인딩
var img1, img2;
document.body.onclick = 함수(e){
var el = document.all?event.srcElement:e.target;
if(el.parentNode.tagName!='TD'){
반품;
}
만약(!img1){
img1 = 엘;
}
또 다른{
img2 = 엘;
}
el.style.border = '단단한 #3399FF 3px';
el = el.parentNode;
if(el.innerHTML==''){
p1 = p2 = e1 = e2 = null;
}
var r = el.parentNode.rowIndex +1;
var c = el.cellIndex +1;
if(p1==널){
//el.childNodes[0].style.border = 'solid #ccc 3px';
p1 = {x:c, y:r};
e1 = 엘;
}
또 다른{
p2 = {x:c, y:r};
e2 = 엘;
if(!equal(p1, p2)&&e1.innerHTML==el.innerHTML){
var 경로 = getPath(p1, p2);
if(경로!=null){
e1.innerHTML = e2.innerHTML = '';
arr[p1.y][p1.x] = arr[p2.y][p2.x] = 0;
}
}
if(t1){t1.style.BackgroundColor = '';}
t1 = e1;
if(t2){t2.style.BackgroundColor = '';}
t2 = e2;
img1.style.border = '단단한 #fff 3px';
img2.style.border = '단단한 #fff 3px';
p1 = p2 = e1 = e2 = img1 = img2 = null;
t1.style.BackgroundColor = t2.style.BackgroundColor = '라이트핑크';
}
}
}
</script>
<body onload="init();">
js Lianliankan 완벽한 주석 버전<br />
<테이블 id="tbl" cellpacing="0" cellpadding="0">
</table>
</body>
</html>