Não tenho nada para fazer, então também escrevi um javascript para Lianliankan. Os comentários são relativamente completos. Amigos que desejam aprender devem lê-lo.
A parte mais difícil do Lian Lian Kan é provavelmente a busca do caminho, que é ver se existe um caminho transitável entre os dois pontos clicados com o mouse. Eu vi o método de escrita recursiva de alguém e senti coceira, então descobri e descobri que não é tão difícil sem recursão.
A busca de caminho é analisada do simples ao difícil. Primeiro, analise se uma linha reta pode ser conectada em uma linha reta, depois analise se dois pontos em uma linha reta podem ser conectados girando duas voltas e, finalmente, analise a situação quando não o são. em linha reta.
Testado em IE6, IE8, firefox3.0.3.
Copie o código do código da seguinte forma:
<html>
<cabeça>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Código-fonte JS Lianliankan versão anotada perfeita</title>
</head>
<estilo>
mesa{
colapso da fronteira: colapso;
}
td{
borda: sólida #ccc 1px;
altura: 36px;
largura: 36px;
cursor: ponteiro;
}
td img{
altura: 30px;
largura: 30px;
borda: sólida #fff 3px;
/*
filtro: alfa(opacidade=80);
-moz-opacidade: 0,8;
opacidade: 0,8;
*/
}
</estilo>
<roteiro>
//A parte seguinte é a parte do algoritmo de busca de caminho e não tem nada a ver com a camada de apresentação
//variáveis globais
var X = 16; //Número total de linhas
var Y = 14;
var tipos = 15; //Tipos de gráficos
//matriz de layout
//Para conveniência do algoritmo, a primeira linha, a primeira coluna, a última linha e a última coluna da matriz são todas marcadas como 0, o que é um caminho natural.
var arr = novo Array(Y);
var tbl; //Exibe o elemento tabela do layout
var p1 = null;//As coordenadas do primeiro ponto usado no caminho de pesquisa
var p2 = null;//As coordenadas do segundo ponto usado no caminho de pesquisa
var e1 = null;//O elemento correspondente ao primeiro ponto
var e2 = null;//O elemento correspondente ao segundo ponto
//Pesquisa de caminho, dados dois pontos, procura um caminho
//O caminho é representado por pontos conectáveis
função getPath(p1, p2){
//Classifique p1 e p2 antes de iniciar a pesquisa para que p2 fique o mais à direita possível de p1.
//Isso pode simplificar o algoritmo
se(p1.x>p2.x){
var t = p1;
p1 =p2;
p2 =t;
}
senão if(p1.x==p2.x){
se(p1.y>p2.y){
var t = p1;
p1 =p2;
p2 =t;
}
}
//Ao analisar a relação posicional entre os dois pontos em Lianliankan, analisamos gradualmente cada tipo, do simples ao difícil.
//O primeiro tipo, se dois pontos estão em linha reta e se os dois pontos podem ser conectados por uma linha reta
if((onlineY(p1, p2)||onlineX(p1, p2)) && hasLine(p1, p2)){
status = 'tipo 1';
retornar [p1,p2];
}
//O segundo tipo, se algum dos dois pontos estiver completamente cercado, não funcionará.
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}) ){
status = 'tipo 2';
retornar nulo;
}
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}) ){
status = 'tipo 2';
retornar nulo;
}
//O terceiro tipo, dois pontos estão em uma linha reta, mas não podem ser conectados por uma linha reta
var pt0, pt1, pt2, pt3;
//Se todos estiverem no eixo x, verifica os caminhos possíveis da esquerda para a direita,
//Construa 4 vértices pt0, pt1, pt2, pt3 de cada vez e verifique se eles estão conectados entre si
if(onlineX(p1, p2)){
for(var i=0; i<Y; i++){
se(eu==p1.y){
continuar;
}
pt0 = p1;
pt1 = {x: p1.x, y: i};
pt2 = {x: p2.x, y: i};
pt3 = p2;
//Se o vértice não estiver vazio, a estrada está bloqueada.
if(!isEmpty(pt1) || !isEmpty(pt2)){
continuar;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
status = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')' ;
retornar [pt0, pt1, pt2, pt3];
}
}
}
//Se todos estiverem no eixo y, verifica os caminhos possíveis de cima para baixo,
//Construa 4 vértices pt0, pt1, pt2, pt3 de cada vez e verifique se eles estão conectados entre si
if(on-lineY(p1, p2)){
for(var j=0; j<X; j++){
se(j==p1.x){
continuar;
}
pt0 = p1;
pt1 = {x:j, y:p1.y};
pt2 = {x:j, y:p2.y};
pt3 = p2;
//Se o vértice não estiver vazio, a estrada está bloqueada.
if(!isEmpty(pt1) || !isEmpty(pt2)){
continuar;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
status = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')' ;
retornar [pt0, pt1, pt2, pt3];
}
}
}
//O quarto tipo, os dois pontos não estão em linha reta.
//Verifica os caminhos possíveis verticalmente primeiro
//Da mesma forma, construa 4 vértices de cada vez para ver se é transitável
for(var k=0; k<Y; k++){
pt0 = p1;
pt1 = {x:p1.x, y:k};
pt2 = {x:p2.x, y:k};
pt3 = p2;
status = '(x:' + pt0.x + ',y:' + pt0.y + ')' + ', (x:' + pt1.x + ',y:' + pt1.y + ')' + ', (x:' + pt2.x + ',y:' + pt2.y + ')' + ', (x:' + pt3.x + ',y:' + pt3.y + ')' ;
//Caso especial, se pt0 e pt1 coincidem
if(igual(pt0,pt1)){
//Se pt2 não estiver vazio, este caminho está bloqueado
if(!isEmpty(pt2)){
continuar;
}
if( hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
retornar [pt1, pt2, pt3];
}
outro{
continuar;
}
}
//Caso especial, se pt2 e pt3 se sobrepõem
senão if(igual(pt2,pt3)){
//Se pt1 não estiver vazio, este caminho está bloqueado
if(!isEmpty(pt1)){
continuar;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) ){
retornar [pt0, pt1, pt2];
}
outro{
continuar;
}
}
//Se nem pt1 nem pt2 estiverem vazios, não funcionará.
if(!isEmpty(pt1) || !isEmpty(pt2)){
continuar;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
retornar [pt0, pt1, pt2, pt3];
}
}
//Verifica possíveis caminhos horizontalmente
for(var k=0; k<X; k++){
pt0 = p1;
pt1 = {x:k, y:p1.y};
pt2 = {x:k, y:p2.y};
pt3 = p2;
status = '(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(igual(pt0,pt1)){
if(!isEmpty(pt2)){
continuar;
}
if( hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
retornar [pt1, pt2, pt3];
}
}
if(igual(pt2,pt3)){
if(!isEmpty(pt1)){
continuar;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) ){
retornar [pt0, pt1, pt2];
}
}
if(!isEmpty(pt1) || !isEmpty(pt2)){
continuar;
}
if( hasLine(pt0, pt1) && hasLine(pt1, pt2) && hasLine(pt2, pt3) ){
retornar [pt0, pt1, pt2, pt3];
}
}
//status='tipo4';
retornar nulo;
/************ tipo final 4 **************/
}
função igual(p1, p2){
retornar ((p1.x==p2.x)&&(p1.y==p2.y));
}
função on-lineX(p1, p2){
retornar p1.y==p2.y;
}
função on-lineY(p1, p2){
retornar p1.x==p2.x;
}
função estáVazia(p){
retornar (arr[py][px]==0);
}
função hasLinha(p1, p2){
if(p1.x==p2.x&&p1.y==p2.y){
retornar verdadeiro;
}
if(on-lineY(p1, p2)){
var i = p1.y>p2.y?p2.y:p1.y;
eu = eu+1;
var máx = p1.y>p2.y?p1.y:p2.y;
for(; i<máx; i++){
var p = {x: p1.x, y: i};
if(!isEmpty(p)){
quebrar
}
}
se(eu==máx){
retornar verdadeiro;
}
retornar falso;
}
senão if(onlineX(p1, p2)){
var j = p1.x>p2.x?p2.x:p1.x;
j = j+1;
var máx = p1.x>p2.x?p1.x:p2.x;
for(; j<máx; j++){
var p = {x: j, y: p1.y};
if(!isEmpty(p)){
quebrar
}
}
se(j==máx){
retornar verdadeiro;
}
retornar falso;
}
}
//A parte seguinte é a parte da camada de apresentação, incluindo desenho, inicialização da matriz, vinculação de eventos do mouse...
função $(id){retornar documento.getElementById(id)}
var t1, t2; //para teste
//Caminho base da imagem
var IMG_PATH = '//www.VeVB.COm';
//inicialização
função inicialização(){
//Constrói biblioteca de imagens
var imgs = new Array(30);
for(var i=1; i<=30; i++){
imgs[i] = 'r_' + i + '.gif';
}
tbl = $('tbl');
//Constrói tabela
for(var linha=0;linha<Y-2;linha++){
var tr=tbl.insertRow(-1);
for(var col=0;col<X-2;col++) {
var td=tr.insertCell(-1);
}
}
//Constrói matriz
for(var i=0; i<Y; i++){
arr[i] = nova Matriz(X);
for(var j=0; j<X; j++){
arr[i][j] = 0;
}
}
var total = (X-2)*(Y-2);
var tmp = new Array(total); //Usado para gerar posições aleatórias
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()*tipos) + 1;
tmp[i] = t;
enquanto(verdadeiro){
var c = Math.floor(Math.random()*(total-i)) + i;
if(tmp[c]==0){
tmp[c] = t;
quebrar;
}
}
}
}
varc = 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]] + '" />';
}
}
// Vincula eventos do mouse
var img1, img2;
document.body.onclick=função(e){
var el = document.all?event.srcElement:e.target;
if(el.parentNode.tagName!='TD'){
retornar;
}
se(!img1){
img1 = el;
}
outro{
img2 = el;
}
el.style.border = 'sólido #3399FF 3px';
el = el.parentNode;
if(el.innerHTML==''){
p1 = p2 = e1 = e2 = nulo;
}
var r = el.parentNode.rowIndex +1;
var c = el.cellIndex +1;
if(p1==nulo){
//el.childNodes[0].style.border = 'solid #ccc 3px';
p1 = {x:c, y:r};
e1 = el;
}
outro{
p2 = {x:c, y:r};
e2 = el;
if(!equal(p1, p2)&&e1.innerHTML==el.innerHTML){
var caminho = getPath(p1, p2);
if(caminho!=nulo){
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 = 'sólido #fff 3px';
img2.style.border = 'sólido #fff 3px';
p1 = p2 = e1 = e2 = img1 = img2 = nulo;
t1.style.backgroundColor = t2.style.backgroundColor = 'lightpink';
}
}
}
</script>
<body onload="init();">
js Lianliankan versão anotada perfeita<br />
<table id="tbl" cellpacing="0" cellpadding="0">
</tabela>
</body>
</html>