freecodecamp项目---tictactoe

一:介绍

这个项目是做一个人机对战的井字棋,一开始,完全不知道如何下手,不知道该怎么完成这个功能,最后再github上找了个项目跟着看,一看js代码,各种函数,作者也没有什么注释,看着还是头疼,但是没有办法,只有硬着头皮一个个函数的看过去,分析这个函数时做什么的,看着看着突然觉得还是挺简单的~但是大多数的时候我们都被自己吓怕了,所以不管多难,都要尝试去做,说不定就做出来了呢。当然这个作者的js代码只有三百多行,所以也不算多,只是一个小项目~

该项目在codepen上的地址:https://codepen.io/lightforme/full/JJLGwq/

二:知识点

  • 1.confirm(message):该方法用于显示一个带有指定消息和OK、取消按钮的对话框;
  • 2.window.location:对象用于获得当前页面的地址 (URL),window.location.reload可以将页面重新加载;
  • 3.z-index:只有当position为非默认值时,该值才有效,只越大越层叠在上面,并且被覆盖的部分不能被点击到;
  • 4.e.preventDefault:取消和事件相关联的默认动作;
  • 5.原生js中可以直接重新设置事件方法进行覆盖,但是jQuery中不行,jQuery中需要取消事件方法需要使用.unbind()方法,不加参数是移出所有的事件方法,加参数指定移出事件方法;
  • 6.在codepen中window.location对象被禁用了,所以重载页面可以使用location = location;来替代;

三:代码
html:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>tictoctie game</title>
		<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
		<link rel="stylesheet" href="css/tictoctie.css" />
	</head>
	<body>
		<div class="container">
			<div class="gameboard">
				<ul class="grid-list">
					<li class="grid grid-0"></li>
					<li class="grid grid-1"></li>
					<li class="grid grid-2"></li>
					<li class="grid grid-3"></li>
					<li class="grid grid-4"></li>
					<li class="grid grid-5"></li>
					<li class="grid grid-6"></li>
					<li class="grid grid-7"></li>
					<li class="grid grid-8"></li>
				</ul>
			</div>
		</div>
		
		<div class="bg">
    	</div>
		
		<div class="choose-panel">
			<div class="choose-player">
				<p>选择角色:X OR O?</p>
    			<div class="choose-btn">
    				<button class="btn btn-default xobtn" id="x-btn">X</button><button class="btn btn-default xobtn" id="o-btn">O</button>
    			</div>
			</div>
			<div class="choose-first">
				<p>设置先手:</p>
                <div class="choose-btn">
                    <button class="btn btn-default firstbtn" id="computer">电脑</button><button class="btn btn-default firstbtn" id="user">玩家</button>
                </div>
			</div>
		</div>
		
		<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
		<script src="js/tictpctie.js"></script>
	</body>
</html>

css:

* {
	margin: 0px;
	padding: 0px;
}

.gameboard {
	width: 480px;
	height: 450px;
	margin-left: auto;
	margin-right: auto;
	margin-top: 200px;
	background-color: #000;
}

.gameboard ul {
	list-style: none;
	height: 480px;
	padding: 15px;
}

.grid {
	width: 32.4%;
	height: 30.5%;
	float: left;
	border: 1px solid #E1F5A9;
}

.gameboard li {
	cursor: pointer;
	color: #F9F9F9;
	text-align: center;
	line-height: 138px;
	font-size: 2em;
}

.grid-0, .grid-3, .grid-6 {
	border-left: none;
}

.grid-0, .grid-1, .grid-2 {
	border-top: none;	
}

.grid-2, .grid-5, .grid-8 {
	border-right: none;
}

.grid-6, .grid-7, .grid-8 {
	border-bottom: none;
}

.bg {
	/*display: none;*/
	position: absolute;
	top: 0%;
	left: 0%;
	width: 100%;
	height: 100%;
	background-color: black;
	z-index:1001;
	-moz-opacity: 0.7;
	opacity:.70;
	filter: alpha(opacity=70);
}

.choose-panel {
	position: absolute;
	top: 0;
	left: 0;
	bottom: 0;
	right: 0;
	width: 560px;
	height: 200px;
	margin: auto;
	background-color: #FFF;
	margin-top: 200px;
	z-index: 1002;
	border-radius: 25px;
}

.choose-panel p {
	font-size: 2em;
	text-align: center;
	padding-top: 30px;
}

.choose-btn {
	text-align: center;
}

.btn {
	margin: 5px;
	padding:5px;
}

.choose-first {
	display: none;
}

javascript:

/*game逻辑分析
 * 		新建一个game的构造函数,并给该构造函数的原型对象prototype添加两个属性:init/play
 * 
 * 		1.点击选择角色按钮,选择角色,关闭选择角色面板,打开选择先手面板;
 * 		2.选择先手,若是电脑先手,调用对象的play()函数;
 * 		3.设置点击棋盘位置的点击事件,每次点击玩更新棋盘相应处的棋子,并调用play()函数,让电脑落子;
 * 		4.play()函数逻辑:判断是否下一手即可获胜,若能找到落子位置落子
 * 						否则,判断下一手player是否将要获胜,若是,找到落子位置落子;
 * 						否则,判断是否是第一手,若是,落子棋盘正中间;
 * 						否则,收集棋盘其余未落子的位置,并随机选择落子位置落子
 */

$(function(){
	var running = false,        
		computerVal = -1,        
		playerVal = 1,           
		computer,player,
		copEnd = false,
		winResult = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]],
		panel = [0,0,0,0,0,0,0,0,0];
	
	//设置角色
	function setPlayer(val){
		computer = val === 'O' ? 'X' : 'O';
		$(".choose-player").css("display","none");
		$(".choose-first").css("display","block");
	};
	
	//通过类名获得位置
	function getPos(val){
		return val.split(" ")[1].split("-")[1];
	};
	
	//判断玩家是否胜利
	function playerWin(){
		for(var i = 0;i <winResult.length;i++){
			var winCount = 0;
			for(var j = 0;j < winResult[i].length;j++){
				if(panel[winResult[i][j]] == 1){
					winCount++;
				};
			};
			if(winCount == 3){
				return true;
			};
		};
		return false;
	};
	
	//判断电脑是否胜利
	function computerWin(){
		for(var i = 0;i <winResult.length;i++){
			var winCount = 0;
			for(var j = 0;j < winResult[i].length;j++){
				if(panel[winResult[i][j]] == (-1)){
					winCount++;
				};
			};
			if(winCount == 3){
				return true;
			};
		};
		return false;
	};
	
	//判断棋盘是否下满
	function end(){
		var count = 0;
		for(var i = 0;i < panel.length;i++){
			if(panel[i] != 0){
				count++;
			};
		};
		return (count == 9);
	};
	
	//更新棋盘棋子
	function updateRole(pos,val){
		var targetClass = '.grid-' + pos;
		var who = val == 1 ? player : computer;
		$(targetClass).html(who);
		$(targetClass).unbind("click");
		panel[pos] = val;
		if(playerWin()){
			copEnd = true;
			if(confirm("玩家胜利,是否重开一局?")){
				window.location.reload();
			};
		}else if(computerWin()){
			copEnd = true;
			if(confirm("电脑胜利 ,是否重开一局?")){
				window.location.reload();
			};
		}else if(end()){
			copEnd = true;
			if(confirm("平局,是否重开一局?")){
				window.location.reload();
			};
		};
	};
	
	function compOneEmp(arr){
		var empCount = 0;
		var compCount = 0;
		for(var i = 0;i < arr.length;i++){
			if(panel[arr[i]] == 0){
				empCount++;
			};
			if(panel[arr[i]] == (-1)){
				compCount++;
			};
		};
		if(compCount == 2){
			return (empCount == 1);
		};
		
	};
	
	//电脑是否可以攻击
	function canAttack(){
		for(var i = 0;i < winResult.length;i++){
			if(compOneEmp(winResult[i])){
				return true;
			};
		};
		return false;
	};
	
	function findAttackPos(){
		for(var i = 0;i<winResult.length;i++){
			if(compOneEmp(winResult[i])){
				for(var j=0;j<winResult[i].length;j++){
					if(panel[winResult[i][j]] == 0){
						return winResult[i][j]; 
					};
				};
			};
		};
		return false;
	};
	
	//电脑是否需要防守
	function canDefend(){
		for(var i = 0;i < winResult.length;i++){
			if(playOneEmp(winResult[i])){
				return true;
			};
		};
		return false;
	};
	
	function playOneEmp(arr){
		var empCount = 0;
		var playCount = 0;
		for(var i = 0;i < arr.length;i++){
			if(panel[arr[i]] == 0){
				empCount++;
			};
			if(panel[arr[i]] == 1){
				playCount++;
			};
		};
		if(playCount == 2){
			return (empCount == 1);
		};
	};
	
	function findDefendPos(){
		for(var i = 0;i<winResult.length;i++){
			if(playOneEmp(winResult[i])){
				for(var j=0;j<winResult[i].length;j++){
					if(panel[winResult[i][j]] == 0){
						return winResult[i][j]; 
					};
				};
			};
		};
		return false;
	};
	
	function firstStep(){
		return !running;
	};
	
	function specialPos(){
		if(panel[4] == 0){
			return true;
		};
		return false;
	};
	
	function collectEmp(){
		var arr = [];
		for(var i = 0;i < panel.length;i++){
			if(panel[i] == 0){
				arr.push(i);
			};
		};
		return arr;
	};
	
	//建立构造器函数
	var ticToctie = function(){};
	
	//给构造函数原型添加方法
	ticToctie.prototype = {
		init: function(){
			var self = this;
			$(".choose-player .btn").click(function(){
				player = $(this).html();
				
				setPlayer(player);
			});
			
			$(".choose-first .btn").click(function(){
				$(".bg").css('display', 'none');
				$(".choose-panel").css("display","none");
				var whoFirst = $(this).attr("id");
				//若不是,将running置为true,防止影响后面电脑落子
				if(whoFirst == 'computer'){
					self.play();
				}else{
					running = true;
				};
			});
			$(".grid").click(function(){
				var pos = getPos($(this).attr('class'));
				
				updateRole(pos,playerVal);
				if(!copEnd){
					self.play();
				};
				//并取消此处可点击
			});
		},
		play: function(){
			if(canAttack()){
				let pos = findAttackPos();
				updateRole(pos,computerVal);
				return;
			};
			if(canDefend()){
				let pos = findDefendPos();
				updateRole(pos,computerVal);
				return;
			};
			if(firstStep()){
				running = true;
				updateRole(4,computerVal);
				return;
			};
			if(specialPos()){
				updateRole(4,computerVal);
				return;
			};
			var arr = collectEmp();
			var pos = Math.floor(Math.random() * arr.length);
			updateRole(arr[pos],computerVal);
			return;
		}
	};
	
	//创建一个构造函数实例
	var competition = new ticToctie();
	competition.init();
});


如果有发现问题或者有好的建议,请在评论中指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值