我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Typescript井字棋的项目实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Typescript井字棋的项目实现

单元格点击

效果:点击棋盘的任意单元格,单元格显示×(默认)
思路:
1.获取到所有的单元格列表
2.遍历单元格列表,给每一个单元格添加点击事件
3.给当前被点击的单元格添加类名 x

引入js
1、新建 index.ts 文件,同时在终端中执行 tsc --watch index.ts 来生成 js 文件
2、demo.html 中在 body 结束标签前,引入 index.js

<script class="lazy" data-src="./index.js"></script>

编写代码


let cells = document.querySelectorAll('.cell')
cells.forEach(function (item, index) {
    let cell = item as HTMLDivElement;
    cell.addEventListener('click',function (event) {
        let target = event.target as HTMLDivElement
        target.classList.add('x')
    })
})

在这里插入图片描述

优化
1、防止单元格重复点击,在添加事件时,使用 once 属性,让单元格只能被点击一次
2、使用函数声明形式的事件处理程序(代码多了后,代码结构会更清晰)


let cells = document.querySelectorAll('.cell')
cells.forEach(function (item, index) {
    let cell = item as HTMLDivElement;
    cell.addEventListener('click', clickCell, {once: true})
})

//棋盘中单元格的click事件处理程序
function clickCell(event) {
    let target = event.target as HTMLDivElement
    target.classList.add('x')
}

切换玩家

效果:玩家(x)和玩家(o)轮流交替下棋
思路:
1.创建一个存储当前玩家的变量(currentPlayer),默认值为:x
2.将添加给单元格时写死的类名x,替换为变量(currentPlayer)的值
3.切换到另一个玩家:在添加类名(下棋完成一步)后,根据当前玩家,得到另外一个玩家
4.处理下一步提示:移除游戏面板中的x和o类名,添加下一个玩家对应的类名

let cells = document.querySelectorAll('.cell')
let currentPlayer = 'x'
let gameBoard = document.querySelector('#bord')

cells.forEach(function (item, index) {
    let cell = item as HTMLDivElement;
    cell.addEventListener('click', clickCell, {once: true})
})

//棋盘中单元格的click事件处理程序
function clickCell(event) {
    let target = event.target as HTMLDivElement
    target.classList.add(currentPlayer)
    currentPlayer = currentPlayer === 'x'?'o':'x'
    gameBoard.classList.remove('x','o')
    gameBoard.classList.add(currentPlayer)
}

在这里插入图片描述

使用枚举

使用变量(currentPlayer)处理当前玩家,存在的问题:
1、变量的类型是 string,它的值可以是任意字符串
如果不小心写错了(o→0),代码不会报错,但功能就无法实现了,并且很难找错。也就是 string 类型的变量,取值太宽泛,无法很好的限制值为 x 和 o

enum Player {
    X = 'x',
    O = 'o'
}
let cells = document.querySelectorAll('.cell')
let currentPlayer = Player.X
let gameBoard = document.querySelector('#bord')

console.log(cells)
cells.forEach(function (item, index) {
    let cell = item as HTMLDivElement;
    cell.addEventListener('click', clickCell, {once: true})
})

//棋盘中单元格的click事件处理程序
function clickCell(event) {
    let target = event.target as HTMLDivElement
    target.classList.add(currentPlayer)
    currentPlayer = currentPlayer === Player.X ? Player.O : Player.X
    gameBoard.classList.remove(Player.X, Player.O)
    gameBoard.classList.add(currentPlayer)
}

游戏判赢

思路

判赢的思路
判断棋盘中,横、竖、斜(对角线)是否存在三个相同的 x 或 o,只要有一个满足条件,就说明 x 或 o 获胜了
如果所有单元格都有内容,但没有获胜的情况,就说明是平局

我们打印页面上的单元格,发现每个单元格都有索引

console.log(cells)

在这里插入图片描述

在这里插入图片描述

这样我们可以使用单元格索引,来表示每种获胜情况(使用数组来存储,比如:[0,1,2])

所有获胜情况:
:[0,1,2]、[3,4,5]、[6,7,8]
:[0,3,6]、[1,4,7]、[2,5,8]
:[0,4,8]、[2,4,6]

所以每次判赢的时候,都需要判断这8种情况。所以我们可以使用一个“大”数组(外层),来存储这 8 种情况(因为每次判赢都要判断所有情况)

判断过程:
遍历这个大数组,分别判断每一种情况对应的3个单元格元素,是否都是相同的 x 或 o 类名,只要有一种情况满足,就说明获胜了

单元格元素列表说明

单元格元素列表(cells),实际上是一个伪数组(伪数组的特征:具有长度(length)属性和索引),为什么它不是一个真正的数组呢,我们把鼠标放到 cells 上可以看到类型是 NodeListOf<Element>

在这里插入图片描述

伪数组的操作:

1、通过索引获取元素

console. log(cells[0])
console. log (cells[1])

2、使用for循环遍历(推荐使用 forEach 方法)

for ( let i = 0; i < cells.length; i++){
	console.log(cells[i])
)

封装判赢函数

封装函数,主要考虑:参数和返回值。
该函数的返回值是什么? 布尔值(判断是否获胜)
该函数的有参数吗?是什么?当前玩家
什么时候判赢?玩家点击单元格下棋后

说明:判赢,就是在判断当前玩家下棋后是否获胜(玩家没下棋,不可能获胜,不需要判断)

//声明函数:
function checkwin (player: Player) : boolean { }
//调用函数:
let iswin = checkwin (currentPlayer)

下面我们按照步骤来封装这个函数:
1、声明函数(checkwin),指定参数(player),类型注解为: Player枚举
2、指定返回值:现在函数中写死返回 true 或 false
3、在给单元格添加类名后(下棋后),调用函数 checkwin,拿到函数返回值
4、判断函数返回值是否为 true,如果是,说明当前玩家获胜了

......

//棋盘中单元格的click事件处理程序
function clickCell(event) {
    let target = event.target as HTMLDivElement
    target.classList.add(currentPlayer)
    //调用判赢函数,判断是否获胜
    let isWin = checkWin(currentPlayer)
    if(isWin){
        console.log(currentPlayer+'赢了')
    }
    //根据当前玩家得到另一个玩家
    currentPlayer = currentPlayer === Player.X ? Player.O : Player.X
    //处理下一步提示
    ......
}
//封装判赢函数
function checkWin(player:Player):boolean {
    return true
}

接下来实现判赢函数
思路:
1、遍历判赢数组,分别判断每种情况对应的 3 个单元格元素,是否同时包含当前玩家的类名
2、在 some 方法的回调函数中,获取到每种获胜情况对应的 3 个单元格元素

问题:使用哪种方式遍历数组呢?
只要有一种情况满足,就表示玩家获胜,后续的情况就没有必要再遍历,因此,数组遍历时可以终止

判赢函数的返回值是布尔类型,如果玩家获胜(有一种情况满足),就返回 true;否则,返回 false

数组的 some 方法:1、遍历数组时可终止;2、方法返回值为 true 或 false

3、判断这 3 个单元格元素是否同时包含当前玩家的类名

4、如果包含(玩家获胜),就在回调函数中返回 true 停止循环;否则,返回false,继续下一次循环

let winsArr = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
//封装判赢函数
function checkWin(player: Player): boolean {
    let isWin = winsArr.some(function (win) {
        let cellIndex1 = cells[win[0]] as HTMLDivElement;
        let cellIndex2 = cells[win[1]] as HTMLDivElement;
        let cellIndex3 = cells[win[2]] as HTMLDivElement;
        if (cellIndex1.classList.contains(player) && cellIndex2.classList.contains(player) && cellIndex3.classList.contains(player)) {
            return true
        } else {
            return false
        }
    })
    return isWin;
}

在这里插入图片描述

可以优化:

function checkWin(player: Player): boolean {
    return winsArr.some(function (win) {
        let cellIndex1 = cells[win[0]];
        let cellIndex2 = cells[win[1]];
        let cellIndex3 = cells[win[2]];
        if (hasClass(cellIndex1, player) && hasClass(cellIndex2, player) && hasClass(cellIndex3, player)) {
            return true
        } else {
            return false
        }
    })
}

function hasClass(el: Element, name: string): boolean {
    return el.classList.contains(name)
}

判断平局

思路:创建变量(steps),记录已下棋的次数,判断 steps 是否等于 9,如果等于说明平局

注意:
先判赢,再判平局

步骤:
1、创建变量(steps) ,默认值为 0
2、在玩家下棋后,让 steps 加 1
3、在判赢的代码后面,判断 steps 是否等于 9
4、如果等于 9 说明是平局,游戏结束,就直接 return,不再执行后续代码

//记录已下棋的步数
let steps = 0

//棋盘中单元格的click事件处理程序
function clickCell(event) {
    let target = event.target as HTMLDivElement
    target.classList.add(currentPlayer)
    steps++
    //调用判赢函数,判断是否获胜
    let isWin = checkWin(currentPlayer)
    if (isWin) {
        console.log(currentPlayer + '赢了')
        return;
    }
    //判断平局
    if (steps === 9) {
        console.log('平局了')
        return
    }
    //根据当前玩家得到另一个玩家
    ......
}

展示获胜信息

效果:在获胜或平局时,展示相应信息
步骤:
1、获取到与获胜信息相关的两个DOM元素:①#message#winner
2、显示获胜信息面板(通过style属性实现)
3、展示获胜信息:如果获胜,展示“x赢了!” 或 “o赢了!”;如果是平局,展示“平局”

let messageDiv = document.querySelector('#message') as HTMLDivElement
let winner = document.querySelector('#winner') as HTMLParagraphElement

//棋盘中单元格的click事件处理程序
function clickCell(event) {
    ......
    if (isWin) {
        messageDiv.style.display = "block"
        winner.innerText = currentPlayer + '赢了'
        return;
    }
    //判断平局
    if (steps === 9) {
        messageDiv.style.display = "block"
        winner.innerText = '平局了'
        return
    }
   	......
}

在这里插入图片描述

重新开始游戏

效果:点击重新开始按钮,重新开始下棋游戏

说明:重新开始游戏,实际上就是要重置游戏中的所有数据,恢复到初始状态。比如:隐藏获胜信息、重置下棋次数、清空棋盘等等

步骤:
1、获取到重新开始按钮(#restart),并绑定点击事件
2、在点击事件中,重置游戏数据
3、隐藏获胜信息、清空棋盘、移除单元格点击事件、重新给单元格绑定点击事件
4、重置下棋次数、重置默认玩家为 x、重置下棋提示为 x

//获取重新开始按钮
let restart = document.querySelector('#restart') as HTMLButtonElement
restart.addEventListener('click',startGame)

//重新开始游戏
function startGame() {
    //隐藏获胜信息
    messageDiv.style.display = "none"
    cells.forEach(function (item,index) {
        let cell = item as HTMLDivElement
        //清空棋盘
        cell.classList.remove(Player.X, Player.O)
        //移除点击事件
        cell.removeEventListener('click',clickCell)
        //重新给单元格绑定事件
        cell.addEventListener('click', clickCell, {once: true})
    })
    //重置下棋次数
    steps = 0
    //默认玩家x
    currentPlayer = Player.X
    //重置下一步提示为x
    gameBoard.classList.remove(Player.X,Player.O)
    gameBoard.classList.add(currentPlayer)
}

优化重新游戏功能:
原来,下棋分为:①第—次游戏②重新开始游戏
现在,将第一次游戏,也看做是“重新开始游戏”,就可以去掉第一次游戏时重复的初始化操作了

优化步骤:
1、直接调用函数(startGame) ,来开始游戏
2、移除变量 steps、currentPlayer 的默认值,并添加明确的类型注解
3、移除给单元格绑定事件的代码

完整代码如下:

enum Player {
    X = 'x',
    O = 'o'
}
//获取所有单元格
let cells = document.querySelectorAll('.cell')
//默认玩家
let currentPlayer:Player
//游戏棋盘dom
let gameBoard = document.querySelector('#bord')
//所有获胜可能性
let winsArr = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
//记录已下棋的步数
let steps:number
//获胜信息展示相关dom
let messageDiv = document.querySelector('#message') as HTMLDivElement
let winner = document.querySelector('#winner') as HTMLParagraphElement
//获取重新开始按钮
let restart = document.querySelector('#restart') as HTMLButtonElement
restart.addEventListener('click',startGame)

//调用该函数来初始化游戏,开始游戏
startGame()

//棋盘中单元格的click事件处理程序
function clickCell(event) {
    let target = event.target as HTMLDivElement
    target.classList.add(currentPlayer)
    steps++
    //调用判赢函数,判断是否获胜
    let isWin = checkWin(currentPlayer)
    if (isWin) {
        messageDiv.style.display = "block"
        winner.innerText = currentPlayer + '赢了'
        return;
    }
    //判断平局
    if (steps === 9) {
        messageDiv.style.display = "block"
        winner.innerText = '平局了'
        return
    }
    //根据当前玩家得到另一个玩家
    currentPlayer = currentPlayer === Player.X ? Player.O : Player.X
    //下一步提示
    gameBoard.classList.remove(Player.X,Player.O)
    gameBoard.classList.add(currentPlayer)
}

//封装判赢函数
function checkWin(player: Player): boolean {
    return winsArr.some(function (win) {
        let cellIndex1 = cells[win[0]];
        let cellIndex2 = cells[win[1]];
        let cellIndex3 = cells[win[2]];
        if (hasClass(cellIndex1, player) && hasClass(cellIndex2, player) && hasClass(cellIndex3, player)) {
            return true
        } else {
            return false
        }
    })
}
//是否包含某一样式方法
function hasClass(el: Element, name: string): boolean {
    return el.classList.contains(name)
}

//重新开始游戏
function startGame() {
    //隐藏获胜信息
    messageDiv.style.display = "none"
    //重置下棋次数
    steps = 0
    //默认玩家x
    currentPlayer = Player.X
    //重置下一步提示为x
    gameBoard.classList.remove(Player.X,Player.O)
    gameBoard.classList.add(currentPlayer)

    cells.forEach(function (item, index) {
        let cell = item as HTMLDivElement
        //清空棋盘
        cell.classList.remove(Player.X, Player.O)
        //移除点击事件
        cell.removeEventListener('click',clickCell)
        //重新给单元格绑定事件
        cell.addEventListener('click', clickCell, {once: true})
    })
}

在这里插入图片描述

 到此这篇关于Typescript井字棋的项目实现的文章就介绍到这了,更多相关Typescript 井字棋内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Typescript井字棋的项目实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Typescript井字棋的项目实现

本文主要介绍了Typescript井字棋的项目实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

python实现井字棋游戏

本文实例介绍了python实现井字棋游戏的方法,分享给大家,具体内容如下 windows7下python3.4.0编译运行通过。由于采用了cmd调用,所以与Linux不兼容,无法在Linux下运行。 游戏就是井字棋,小键盘上的数字位置对应棋
2022-06-04

python实现简单的井字棋

本文实例为大家分享了python实现简单的井字棋的具体代码,供大家参考,具体内容如下 使用python实现井字棋游戏,没有具体算法,只是用随机下棋简单实现:import random board = [['+','+','+'],['+',
2022-06-02

纯CSS3实现井字棋游戏的示例

这篇文章给大家分享的是有关纯CSS3实现井字棋游戏的示例的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。运行效果:html
2023-06-08

pygame如何实现井字棋的逻辑思路

这篇文章主要介绍了pygame如何实现井字棋的逻辑思路,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、前言这次我们来实现基本的逻辑,比如判断输赢、玩家和电脑分别下棋的逻辑。
2023-06-14

React中井字棋游戏的实现示例

本文主要介绍了React中井字棋游戏的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

pygame实现井字棋之第二步逻辑实现

一、前言 我们在上一篇博客中实现了九宫格的绘制,为我们打下了基础。 这次我们来实现基本的逻辑,比如判断输赢、玩家和电脑分别下棋的逻辑。 二、下棋 2.1 玩家 我们之前在Lattice类中,有一个stats变量来表示格子的状态,# 0表示初
2022-06-02

C语言如何开发实现井字棋

这篇文章主要为大家展示了“C语言如何开发实现井字棋”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C语言如何开发实现井字棋”这篇文章吧。总体思路井字棋棋盘我们总体可以当成一个二维数组来操作,我们分
2023-06-25

编程热搜

目录