angular实现连连看

说明:

我希望用angular实现连连看

1.生成方格

2.相同图案连接

3.已连接图标隐藏

4.得分系统

5.提示,当你实在找不到的时候,点击提示,可以帮你设置图标高亮

5.重新开始 刷新

6.支持多套图标数组,可以用来设计关卡

效果图:

step1:C:\Users\wangrusheng\PycharmProjects\untitled15\src\app\links\links.component.ts

typescript 复制代码
import { Component, OnInit } from '@angular/core';
import { NgForOf,NgIf } from '@angular/common';

interface BoardCell {
  value: number;
  cleared: boolean;
  selected: boolean;
  x: number;
  y: number;
}

@Component({
  selector: 'app-links',
  templateUrl: './links.component.html',
  imports: [NgForOf,NgIf],
  styleUrls: ['./links.component.css']
})
export class LinksComponent implements OnInit {
  rows = 12;
  cols = 12;
  cellSize = 40;
  board: BoardCell[][] = [];
  firstSelection: { x: number, y: number } | null = null;
  score = 0;
  hintPair: { x: number, y: number }[] | null = null;
  currentPath: { x: number, y: number }[] | null = null;
  readonly EMOJI_LIST = [
  '🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼',
  '🐨', '🐯', '🦁', '🐮', '🐷', '🐸', '🐵', '🐧'

  ];
  readonly EMOJI_LIST2 = [
  '🐤', '🦄', '🐺', '🐗', '🐴', '🦋', '🐌', '🐞',
  '🐝', '🦀', '🐡', '🐬', '🦑', '🐊', '🦓', '🐇'
  ];

  ngOnInit(): void {
    this.initializeGameBoard();
  }

  initializeGameBoard(): void {
    const innerRows = this.rows - 2;
    const innerCols = this.cols - 2;
    const totalInner = innerRows * innerCols;

    if (totalInner % 2 !== 0) {
      console.error('Total number of inner cells must be even.');
      return;
    }

    const tileList: number[] = [];
    const emojiCount = this.EMOJI_LIST.length;
    for (let i = 0; i < totalInner / 2; i++) {
      const emojiIndex = i % emojiCount;
      tileList.push(emojiIndex, emojiIndex);
    }

    for (let i = tileList.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [tileList[i], tileList[j]] = [tileList[j], tileList[i]];
    }

    let index = 0;
    this.board = [];
    for (let i = 0; i < this.rows; i++) {
      this.board[i] = [];
      for (let j = 0; j < this.cols; j++) {
        const isBorder = i === 0 || j === 0 || i === this.rows - 1 || j === this.cols - 1;
        this.board[i][j] = {
          value: isBorder ? -1 : tileList[index++],
          cleared: isBorder,
          selected: false,
          x: i,
          y: j
        };
      }
    }
  }

  handleCellClick(cell: BoardCell): void {
    if (cell.cleared || cell.value === -1) return;

    if (!this.firstSelection) {
      this.firstSelection = { x: cell.x, y: cell.y };
      cell.selected = true;
    } else {
      const secondSelection = { x: cell.x, y: cell.y };
      const firstCell = this.board[this.firstSelection.x][this.firstSelection.y];

      if (this.firstSelection.x === secondSelection.x &&
          this.firstSelection.y === secondSelection.y) {
        firstCell.selected = false;
        this.firstSelection = null;
        return;
      }

      if (firstCell.value === cell.value) {
        const path = this.checkConnectivityWithPath(this.firstSelection, secondSelection);
        if (path) {
          firstCell.cleared = true;
          cell.cleared = true;
          this.score += 10;
          this.currentPath = path;
          setTimeout(() => this.currentPath = null, 500);
        }
      }

      firstCell.selected = false;
      cell.selected = false;
      this.firstSelection = null;
    }
  }

  restart(): void {
    this.score = 0;
    this.hintPair = null;
    this.currentPath = null;
    this.initializeGameBoard();
  }

  hint(): void {
    for (let i = 0; i < this.rows; i++) {
      for (let j = 0; j < this.cols; j++) {
        const cell = this.board[i][j];
        if (cell.cleared || cell.value === -1) continue;

        for (let x = i; x < this.rows; x++) {
          for (let y = (x === i ? j + 1 : 0); y < this.cols; y++) {
            const other = this.board[x][y];
            if (!other.cleared && other.value === cell.value &&
                this.checkConnectivityWithPath({x: i, y: j}, {x, y})) {
              this.hintPair = [{x: i, y: j}, {x, y}];
              setTimeout(() => this.hintPair = null, 2000);
              return;
            }
          }
        }
      }
    }
  }

  isHintCell(cell: BoardCell): boolean {
    return !!this.hintPair?.some(p => p.x === cell.x && p.y === cell.y);
  }

  generatePathD(path: {x: number, y: number}[]): string {
    return path.map((p, i) => {
      const x = p.y * this.cellSize + this.cellSize / 2;
      const y = p.x * this.cellSize + this.cellSize / 2;
      return `${i === 0 ? 'M' : 'L'} ${x} ${y}`;
    }).join(' ');
  }

  private checkConnectivityWithPath(p1: { x: number, y: number }, p2: { x: number, y: number }) {
    const direct = this.directConnection(p1, p2);
    if (direct.result) return direct.path;

    const oneTurn = this.oneTurnConnection(p1, p2);
    if (oneTurn.result) return oneTurn.path;

    const twoTurn = this.twoTurnConnection(p1, p2);
    if (twoTurn.result) return twoTurn.path;

    return null;
  }

  private directConnection(p1: { x: number, y: number }, p2: { x: number, y: number }) {
    // ...保持原有逻辑,返回{ result: boolean, path: [...] }
    // 示例实现:
    if (p1.x === p2.x) {
      const minY = Math.min(p1.y, p2.y);
      const maxY = Math.max(p1.y, p2.y);
      for (let y = minY + 1; y < maxY; y++) {
        if (!this.board[p1.x][y].cleared) return { result: false, path: [] };
      }
      return { result: true, path: [p1, p2] };
    }

    if (p1.y === p2.y) {
      const minX = Math.min(p1.x, p2.x);
      const maxX = Math.max(p1.x, p2.x);
      for (let x = minX + 1; x < maxX; x++) {
        if (!this.board[x][p1.y].cleared) return { result: false, path: [] };
      }
      return { result: true, path: [p1, p2] };
    }

    return { result: false, path: [] };
  }

  private oneTurnConnection(p1: { x: number, y: number }, p2: { x: number, y: number }) {
    // ...保持原有逻辑,返回路径
    // 示例实现:
    const corner1 = { x: p1.x, y: p2.y };
    if (this.board[corner1.x][corner1.y].cleared) {
      const path1 = this.directConnection(p1, corner1);
      const path2 = this.directConnection(corner1, p2);
      if (path1.result && path2.result) {
        return { result: true, path: [...path1.path, ...path2.path.slice(1)] };
      }
    }

    const corner2 = { x: p2.x, y: p1.y };
    if (this.board[corner2.x][corner2.y].cleared) {
      const path1 = this.directConnection(p1, corner2);
      const path2 = this.directConnection(corner2, p2);
      if (path1.result && path2.result) {
        return { result: true, path: [...path1.path, ...path2.path.slice(1)] };
      }
    }

    return { result: false, path: [] };
  }

  private twoTurnConnection(p1: { x: number, y: number }, p2: { x: number, y: number }) {
    // ...保持原有逻辑,返回路径
    // 示例实现:
    for (let x = 0; x < this.rows; x++) {
      const p3 = { x, y: p1.y };
      const p4 = { x, y: p2.y };
      if (this.board[p3.x][p3.y].cleared && this.board[p4.x][p4.y].cleared) {
        const path1 = this.directConnection(p1, p3);
        const path2 = this.oneTurnConnection(p3, p2);
        if (path1.result && path2.result) {
          return { result: true, path: [...path1.path, ...path2.path.slice(1)] };
        }
      }
    }

    for (let y = 0; y < this.cols; y++) {
      const p3 = { x: p1.x, y };
      const p4 = { x: p2.x, y };
      if (this.board[p3.x][p3.y].cleared && this.board[p4.x][p4.y].cleared) {
        const path1 = this.directConnection(p1, p3);
        const path2 = this.oneTurnConnection(p3, p2);
        if (path1.result && path2.result) {
          return { result: true, path: [...path1.path, ...path2.path.slice(1)] };
        }
      }
    }

    return { result: false, path: [] };
  }
}

step2:C:\Users\wangrusheng\PycharmProjects\untitled15\src\app\links\links.component.html

xml 复制代码
<!-- links.component.html -->
<div class="controls">
  <button (click)="hint()">提示</button>
  <button (click)="restart()">重新开始</button>
  <div class="score">得分: {{ score }}</div>
</div>

<div class="board">
  <div class="row" *ngFor="let row of board">
     <div *ngFor="let cell of row"
         class="cell"
         [class.cleared]="cell.cleared"
         [class.selected]="cell.selected"
         [class.hint]="isHintCell(cell)"
         (click)="handleCellClick(cell)">

      <!-- 修改这里:清除后不显示内容 -->
      <span *ngIf="!cell.cleared && cell.value !== -1">
        {{ EMOJI_LIST[cell.value] }}
      </span>

      <div *ngIf="cell.value === -1" class="border-cell"></div>
    </div>

  </div>
  <svg class="path-overlay">
    <path *ngIf="currentPath" [attr.d]="generatePathD(currentPath)" stroke="blue" stroke-width="4" fill="none"/>
  </svg>
</div>

step3:C:\Users\wangrusheng\PycharmProjects\untitled15\src\app\links\links.component.css

css 复制代码
/* links.component.css */
.controls {
  margin-bottom: 20px;
  display: flex;
  gap: 10px;
  align-items: center;
}

.score {
  font-weight: bold;
  color: #333;
}

.board {
  position: relative;
  border: 2px solid #333;
}

.row {
  display: flex;
}

.cell {
  width: 40px;
  height: 40px;
  border: 1px solid #ddd;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  background-color: #fff;
  cursor: pointer;
  transition: background-color 0.2s;
}

.cell.cleared {
  background-color: #f0f0f0;
  opacity: 0.5;
}

.cell.selected {
  background-color: #a0d8ef !important;
}

.cell.hint {
  background-color: #ffeb3b;
}

.path-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

end

相关推荐
闲蛋小超人笑嘻嘻18 分钟前
非父子通信: provide和inject
前端·javascript·vue.js
周亚鑫19 分钟前
vue3 js代码混淆
开发语言·javascript·ecmascript
止观止33 分钟前
不止解构:深入掌握 ES6+ 对象与函数的高级语法糖
前端·javascript·es6
捻tua馔...39 分钟前
antd3的表单实现(HOC解决方案)
前端·javascript·react.js
AllinLin1 小时前
JS中的call apply bind全面解析
前端·javascript·vue.js
POLITE31 小时前
Leetcode 438. 找到字符串中所有字母异位词 JavaScript (Day 4)
javascript·算法·leetcode
创思通信1 小时前
STM32F103C8T6采 DS18B20,通过A7680C 4G模块不断发送短信到手机
javascript·stm32·智能手机
zhougl9961 小时前
vue中App.vue和index.html冲突问题
javascript·vue.js·html
止观止1 小时前
告别全局污染:深入理解 ES Modules 模块化与构建工具
javascript·webpack·vite·前端工程化·es modules
千寻girling2 小时前
面试官: “ 请你讲一下 package.json 文件 ? ”
前端·javascript·面试