导言

在一个风和日丽的一天,看完了疯狂HTML 5+CSS 3+JavaScript讲义,跟着做了书里最后一章的俄罗斯方块小游戏,并做了一些改进,作为自己前端学习的第一站。

游戏效果:

制作思路

因为书里的俄罗斯方块比较普通,太常规了,不是很好看,所以我在网上找了上面那张图片,打算照着它来做。(请无视成品和原图的差距)

然后便是游戏界面和常规的俄罗斯方块游戏逻辑。

接着便是游戏结束界面了。

原本想做个弹出层,但觉得找图片有点麻烦,所以就在网上找了文字特效,套用了一下。

代码实现:

首先是html文件和css文件,主要涉及了布局方面。作为新手,在上面真的是翻来覆去的踩坑。o(╥﹏╥)o

index.html

<!DOCTYPE html>
<html>
<head>
<title>俄罗斯方块</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link rel=stylesheet type="text/css" href="teris.css">
<style type="text/css">
/*导入外部的字体文件*/
@font-face{
font-family:tmb;/*为字体命名为tmb*/
src:url("DS-DIGIB.TTF") format("TrueType");/*format为字体文件格式,TrueType为ttf*/
}
div>span{
font-family:tmb;
font-size:18pt;
color:green;
}
</style>
</head> <body>
<div id="container" class="bg">
<!--ui-->
<div class="ui_bg">
<div style="float:left;margin-right:4px;">
速度:<span id="cur_speed">1</span>
</div>
<div style="float:left;">
当前分数:<span id="cur_points">0</span>
</div>
<div style="float:right;">
最高分数:<span id="max_points">0</span>
</div>
</div>
<canvas id="text" width="500" height="100" style="position:absolute;"></canvas>
<canvas id="stage" width="500" height="100" style="position:absolute;"></canvas>
</div>
<script src='EasePack.min.js'></script>
<script src='TweenLite.min.js'></script>
<script src='easeljs-0.7.1.min.js'></script>
<script src='requestAnimationFrame.js'></script>
<script type="text/javascript" src="jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="teris.js"></script>
</body>
</html>

teris.css

*{
margin:;
padding:;
}
html, body{
width:100%;
height:100%;
} .bg{
font-size:13pt;
background-color:rgb(239, 239, 227);
/*好看的渐变色*/
background-image:radial-gradient(rgb(239, 239, 227), rgb(230, 220, 212));
/*阴影*/
box-shadow:#cdc8c1 -1px -1px 7px 0px;
padding-bottom:4px;
} .ui_bg{
border-bottom:1px #a69e9ea3 solid;
padding-bottom:2px;
overflow:hidden;/*没有这句的话因为子div都设置了float,所以是浮在网页上的,所以父div就没有高度,这句清除了浮动,让父div有了子div的高度*/
}

然后是重头戏,teris.js

游戏变量

//游戏设定
var TETRIS_ROWS = 20;
var TETRIS_COLS = 14;
var CELL_SIZE = 24;
var NO_BLOCK=0;
var HAVE_BLOCK=1;
// 定义几种可能出现的方块组合
var blockArr = [
// Z
[
{x: TETRIS_COLS / 2 - 1 , y:0},
{x: TETRIS_COLS / 2 , y:0},
{x: TETRIS_COLS / 2 , y:1},
{x: TETRIS_COLS / 2 + 1 , y:1}
],
// 反Z
[
{x: TETRIS_COLS / 2 + 1 , y:0},
{x: TETRIS_COLS / 2 , y:0},
{x: TETRIS_COLS / 2 , y:1},
{x: TETRIS_COLS / 2 - 1 , y:1}
],
// 田
[
{x: TETRIS_COLS / 2 - 1 , y:0},
{x: TETRIS_COLS / 2 , y:0},
{x: TETRIS_COLS / 2 - 1 , y:1},
{x: TETRIS_COLS / 2 , y:1}
],
// L
[
{x: TETRIS_COLS / 2 - 1 , y:0},
{x: TETRIS_COLS / 2 - 1, y:1},
{x: TETRIS_COLS / 2 - 1 , y:2},
{x: TETRIS_COLS / 2 , y:2}
],
// J
[
{x: TETRIS_COLS / 2 , y:0},
{x: TETRIS_COLS / 2 , y:1},
{x: TETRIS_COLS / 2 , y:2},
{x: TETRIS_COLS / 2 - 1, y:2}
],
// □□□□
[
{x: TETRIS_COLS / 2 , y:0},
{x: TETRIS_COLS / 2 , y:1},
{x: TETRIS_COLS / 2 , y:2},
{x: TETRIS_COLS / 2 , y:3}
],
// ┴
[
{x: TETRIS_COLS / 2 , y:0},
{x: TETRIS_COLS / 2 - 1 , y:1},
{x: TETRIS_COLS / 2 , y:1},
{x: TETRIS_COLS / 2 + 1, y:1}
]
]; // 记录当前积分
var curScore=0;
// 记录曾经的最高积分
var maxScore=1;
var curSpeed=1;
//ui元素
var curSpeedEle=document.getElementById("cur_speed");
var curScoreEle=document.getElementById("cur_points");
var maxScoreEle=document.getElementById("max_points"); var timer;//方块下落控制 var myCanvas;
var canvasCtx;
var tetris_status;//地图数据
var currentFall;//当前下落的block

游戏界面的完善

//create canvas
function createCanvas(){
myCanvas=document.createElement("canvas");
myCanvas.width=TETRIS_COLS*CELL_SIZE;
myCanvas.height=TETRIS_ROWS*CELL_SIZE;
//绘制背景
canvasCtx=myCanvas.getContext("2d");
canvasCtx.beginPath();
//TETRIS_COS
for(let i=1; i<TETRIS_COLS; i++){
canvasCtx.moveTo(i*CELL_SIZE, 0);
canvasCtx.lineTo(i*CELL_SIZE, myCanvas.height);
}
for(let i=1; i<TETRIS_ROWS; i++){
canvasCtx.moveTo(0, i*CELL_SIZE);
canvasCtx.lineTo(myCanvas.width, i*CELL_SIZE);
}
canvasCtx.closePath();
canvasCtx.strokeStyle="#b4a79d";
canvasCtx.lineWidth=0.6;
canvasCtx.stroke();
//第一行,最后一行,第一列,最后一列粗一点。
canvasCtx.beginPath();
canvasCtx.moveTo(0, 0);
canvasCtx.lineTo(myCanvas.width, 0);
canvasCtx.moveTo(0, myCanvas.height);
canvasCtx.lineTo(myCanvas.width, myCanvas.height);
canvasCtx.moveTo(0, 0);
canvasCtx.lineTo(0, myCanvas.height);
canvasCtx.moveTo(myCanvas.width, 0);
canvasCtx.lineTo(myCanvas.width, myCanvas.height);
canvasCtx.closePath();
canvasCtx.strokeStyle="#b4a79d";
canvasCtx.lineWidth=4;
canvasCtx.stroke();
//设置绘制block时的style
canvasCtx.fillStyle="#201a14";
}

draw canvas

 function changeWidthAndHeight(w, h){
//通过jquery设置css
h+=$("ui_bg").css("height")+$("ui_bg").css("margin-rop")+$("ui_bg").css("margin-bottom")+$("ui_bg").css("padding-top")+$("ui_bg").css("padding-bottom");
$(".bg").css({
"width":w,
"height":h,
"top":0, "bottom":0, "right":0, "left":0,
"margin":"auto"
});
}

change width and height

 //draw blocks
function drawBlocks(){
//清空地图
for(let i=0; i<TETRIS_ROWS;i++){
for(let j=0;j<TETRIS_COLS;j++)
canvasCtx.clearRect(j*CELL_SIZE+1, i*CELL_SIZE+1, CELL_SIZE-2, CELL_SIZE-2);
}
//绘制地图
for(let i=0; i<TETRIS_ROWS;i++){
for(let j=0;j<TETRIS_COLS;j++){
if(tetris_status[i][j]!=NO_BLOCK)
canvasCtx.fillRect(j*CELL_SIZE+1, i*CELL_SIZE+1, CELL_SIZE-2, CELL_SIZE-2);//中间留点缝隙
}
}
//绘制currentFall
for(let i=0;i<currentFall.length;i++)
canvasCtx.fillRect(currentFall[i].x*CELL_SIZE+1, currentFall[i].y*CELL_SIZE+1, CELL_SIZE-2,CELL_SIZE-2);
}

draw block

游戏逻辑

 function rotate(){
// 定义记录能否旋转的旗标
var canRotate = true;
for (var i = 0 ; i < currentFall.length ; i++)
{
var preX = currentFall[i].x;
var preY = currentFall[i].y;
// 始终以第三个方块作为旋转的中心,
// i == 2时,说明是旋转的中心
if(i != 2)
{
// 计算方块旋转后的x、y坐标
var afterRotateX = currentFall[2].x + preY - currentFall[2].y;
var afterRotateY = currentFall[2].y + currentFall[2].x - preX;
// 如果旋转后所在位置已有方块,表明不能旋转
if(tetris_status[afterRotateY][afterRotateX + 1] != NO_BLOCK)
{
canRotate = false;
break;
}
// 如果旋转后的坐标已经超出了最左边边界
if(afterRotateX < 0 || tetris_status[afterRotateY - 1][afterRotateX] != NO_BLOCK)
{
moveRight();
afterRotateX = currentFall[2].x + preY - currentFall[2].y;
afterRotateY = currentFall[2].y + currentFall[2].x - preX;
break;
}
if(afterRotateX < 0 || tetris_status[afterRotateY-1][afterRotateX] != NO_BLOCK)
{
moveRight();
break;
}
// 如果旋转后的坐标已经超出了最右边边界
if(afterRotateX >= TETRIS_COLS - 1 ||
tetris_status[afterRotateY][afterRotateX+1] != NO_BLOCK)
{
moveLeft();
afterRotateX = currentFall[2].x + preY - currentFall[2].y;
afterRotateY = currentFall[2].y + currentFall[2].x - preX;
break;
}
if(afterRotateX >= TETRIS_COLS - 1 ||
tetris_status[afterRotateY][afterRotateX+1] != NO_BLOCK)
{
moveLeft();
break;
}
}
}
if(canRotate){
for (var i = 0 ; i < currentFall.length ; i++){
var preX = currentFall[i].x;
var preY = currentFall[i].y;
if(i != 2){
currentFall[i].x = currentFall[2].x +
preY - currentFall[2].y;
currentFall[i].y = currentFall[2].y +
currentFall[2].x - preX;
}
}
localStorage.setItem("currentFall", JSON.stringify(currentFall));
}
}

旋转

 //按下 下 或 interval到了
function next(){
if(moveDown()){
//记录block
for(let i=0;i<currentFall.length;i++)
tetris_status[currentFall[i].y][currentFall[i].x]=HAVE_BLOCK;
//判断有没有满行的
for(let j=0;j<currentFall.length;j++){
for(let i=0;i<TETRIS_COLS; i++){
if(tetris_status[currentFall[j].y][i]==NO_BLOCK)
break;
//最后一行满了
if(i==TETRIS_COLS-1){
//消除最后一行
for(let i=currentFall[j].y; i>0;i--){
for(let j=0;j<TETRIS_COLS;j++)
tetris_status[i][j]=tetris_status[i-1][j];
}
//分数增加
curScore+=5;
localStorage.setItem("curScore", curScore);
if(curScore>maxScore){
//超越最高分
maxScore=curScore;
localStorage.setItem("maxScore", maxScore);
}
//加速
curSpeed+=0.1;
localStorage.setItem("curSpeed", curSpeed);
//ui输出
curScoreEle.innerHTML=""+curScore;
maxScoreEle.innerHTML=""+maxScore;
curSpeedEle.innerHTML=curSpeed.toFixed(1);//保留两位小数
clearInterval(timer);
timer=setInterval(function(){
next();
}, 500/curSpeed);
}
}
}
//判断是否触顶
for(let i=0;i<currentFall.length;i++){
if(currentFall[i].y==0){
gameEnd();
return;
}
}
localStorage.setItem("tetris_status", JSON.stringify(tetris_status));
//新的block
createBlock();
localStorage.setItem("currentFall", JSON.stringify(currentFall));
}
drawBlocks();
} //右移
function moveRight(){
for(let i=0;i<currentFall.length;i++){
if(currentFall[i].x+1>=TETRIS_ROWS || tetris_status[currentFall[i].y][currentFall[i].x+1]!=NO_BLOCK)
return;
}
for(let i=0;i<currentFall.length;i++)
currentFall[i].x++;
localStorage.setItem("currentFall", JSON.stringify(currentFall));
return;
}
//左移
function moveLeft(){
for(let i=0;i<currentFall.length;i++){
if(currentFall[i].x-1<0 || tetris_status[currentFall[i].y][currentFall[i].x-1]!=NO_BLOCK)
return;
}
for(let i=0;i<currentFall.length;i++)
currentFall[i].x--;
localStorage.setItem("currentFall", JSON.stringify(currentFall));
return;
}
//judge can move down and if arrive at end return 1, if touch other blocks return 2, else, return 0
function moveDown(){
for(let i=0;i<currentFall.length;i++){
if(currentFall[i].y>=TETRIS_ROWS-1 || tetris_status[currentFall[i].y+1][currentFall[i].x]!=NO_BLOCK)
return true;
} for(let i=0;i<currentFall.length;i++)
currentFall[i].y+=1;
return false;
}

上下左右移动

 function gameKeyEvent(evt){
switch(evt.keyCode){
//向下
case 40://↓
case 83://S
next();
drawBlocks();
break;
//向左
case 37://←
case 65://A
moveLeft();
drawBlocks();
break;
//向右
case 39://→
case 68://D
moveRight();
drawBlocks();
break;
//旋转
case 38://↑
case 87://W
rotate();
drawBlocks();
break;
}
}

keydown事件监听

其他的详细情况可以看源代码,我就不整理了。

接下来我们看游戏结束时的特效。因为我也不是很懂,所以在这里整理的会比较详细。当做学习。

 //game end
function gameEnd(){
clearInterval(timer);
//键盘输入监听结束
window.onkeydown=function(){
//按任意键重新开始游戏
window.onkeydown=gameKeyEvent;
//初始化游戏数据
initData();
createBlock();
localStorage.setItem("currentFall", JSON.stringify(currentFall));
localStorage.setItem("tetris_status", JSON.stringify(tetris_status));
localStorage.setItem("curScore", curScore);
localStorage.setItem("curSpeed", curSpeed);
//绘制
curScoreEle.innerHTML=""+curScore;
curSpeedEle.innerHTML=curSpeed.toFixed(1);//保留两位小数
drawBlocks();
timer=setInterval(function(){
next();
}, 500/curSpeed);
//清除特效
this.stage.removeAllChildren();
this.textStage.removeAllChildren();
};
//特效,游戏结束
setTimeout(function(){
initAnim();
//擦除黑色方块
for(let i=0; i<TETRIS_ROWS;i++){
for(let j=0;j<TETRIS_COLS;j++)
canvasCtx.clearRect(j*CELL_SIZE+1, i*CELL_SIZE+1, CELL_SIZE-2, CELL_SIZE-2);
}
}, 200);
//推迟显示Failed
setTimeout(function(){
if(textFormed) {
explode();
setTimeout(function() {
createText("FAILED");
}, 810);
} else {
createText("FAILED");
}
}, 800);
}

上面代码里的localstorage是html5的本地数据存储。因为不是运用很难,所以具体看代码。

整个特效是运用了createjs插件。要引入几个文件。

easeljs-0.7.1.min.js, EasePacj.min.js, requestAnimationFrame.js和TweenLite.min.js
游戏重新开始就要清除特效。我看api里我第一眼望过去最明显的就是removeAllChildren(),所以就选了这个。其他的改进日后再说。

        //清除特效
this.stage.removeAllChildren();
this.textStage.removeAllChildren();
function initAnim() {
initStages();
initText();
initCircles();
//在stage下方添加文字——按任意键重新开始游戏.
tmp = new createjs.Text("t", "12px 'Source Sans Pro'", "#54555C");
tmp.textAlign = 'center';
tmp.x = 180;
tmp.y=350;
tmp.text = "按任意键重新开始游戏";
stage.addChild(tmp);
animate();
}

initAnim

上面初始化了一个stage,用于存放特效,一个textstage,用于形成“FAILED”的像素图片。还有一个按任意键重新游戏的提示。同时开始每隔一段时间就刷新stage。

根据block的位置来初始化小圆点。

 function initCircles() {
circles = [];
var p=[];
var count=0;
for(let i=0; i<TETRIS_ROWS;i++)
for(let j=0;j<TETRIS_COLS;j++)
if(tetris_status[i][j]!=NO_BLOCK)
p.push({'x':j*CELL_SIZE+2, 'y':i*CELL_SIZE+2, 'w':CELL_SIZE-3, 'h':CELL_SIZE-4});
for(var i=0; i<250; i++) {
var circle = new createjs.Shape();
var r = 7;
//x和y范围限定在黑色block内
var x = p[count]['x']+p[count]['w']*Math.random();
var y = p[count]['y']+p[count]['h']*Math.random();
count++;
if(count>=p.length)
count=0;
var color = colors[Math.floor(i%colors.length)];
var alpha = 0.2 + Math.random()*0.5;
circle.alpha = alpha;
circle.radius = r;
circle.graphics.beginFill(color).drawCircle(0, 0, r);
circle.x = x;
circle.y = y;
circles.push(circle);
stage.addChild(circle);
circle.movement = 'float';
tweenCircle(circle);
}
}

initCircles

然后再讲显示特效Failed的createText()。先将FAILED的text显示在textstage里,然后ctx.getImageData.data获取像素数据,并以此来为每个小圆点定义位置。

 function createText(t) {
curText=t;
var fontSize = 500/(t.length);
if (fontSize > 80) fontSize = 80;
text.text = t;
text.font = "900 "+fontSize+"px 'Source Sans Pro'";
text.textAlign = 'center';
text.x = TETRIS_COLS*CELL_SIZE/2;
text.y = 0;
textStage.addChild(text);
textStage.update(); var ctx = document.getElementById('text').getContext('2d');
var pix = ctx.getImageData(0,0,600,200).data;
textPixels = [];
for (var i = pix.length; i >= 0; i -= 4) {
if (pix[i] != 0) {
var x = (i / 4) % 600;
var y = Math.floor(Math.floor(i/600)/4);
if((x && x%8 == 0) && (y && y%8 == 0)) textPixels.push({x: x, y: y});
}
} formText();
textStage.clear();//清楚text的显示
}

CreateText

跟着代码的节奏走,我们现在来到了formtext.

 function formText() {
for(var i= 0, l=textPixels.length; i<l; i++) {
circles[i].originX = offsetX + textPixels[i].x;
circles[i].originY = offsetY + textPixels[i].y;
tweenCircle(circles[i], 'in');
}
textFormed = true;
if(textPixels.length < circles.length) {
for(var j = textPixels.length; j<circles.length; j++) {
circles[j].tween = TweenLite.to(circles[j], 0.4, {alpha: 0.1});
}
}
}

formtext

explode()就是讲已组成字的小圆点给重新遣散。

动画实现是使用了tweenlite.

 function tweenCircle(c, dir) {
if(c.tween) c.tween.kill();
if(dir == 'in') {
/*TweenLite.to 改变c实例的x坐标,y坐标,使用easeInOut弹性函数,透明度提到1,改变大小,radius,总用时0.4s*/
c.tween = TweenLite.to(c, 0.4, {x: c.originX, y: c.originY, ease:Quad.easeInOut, alpha: 1, radius: 5, scaleX: 0.4, scaleY: 0.4, onComplete: function() {
c.movement = 'jiggle';/*轻摇*/
tweenCircle(c);
}});
} else if(dir == 'out') {
c.tween = TweenLite.to(c, 0.8, {x: window.innerWidth*Math.random(), y: window.innerHeight*Math.random(), ease:Quad.easeInOut, alpha: 0.2 + Math.random()*0.5, scaleX: 1, scaleY: 1, onComplete: function() {
c.movement = 'float';
tweenCircle(c);
}});
} else {
if(c.movement == 'float') {
c.tween = TweenLite.to(c, 5 + Math.random()*3.5, {x: c.x + -100+Math.random()*200, y: c.y + -100+Math.random()*200, ease:Quad.easeInOut, alpha: 0.2 + Math.random()*0.5,
onComplete: function() {
tweenCircle(c);
}});
} else {
c.tween = TweenLite.to(c, 0.05, {x: c.originX + Math.random()*3, y: c.originY + Math.random()*3, ease:Quad.easeInOut,
onComplete: function() {
tweenCircle(c);
}});
}
}
}

TweenLite.to函数第一个参数,要做动画的实例,第二个参数,事件,第三个参数,动画改变参数。

Quad.easeInOut()意思是在动画开始和结束时缓动。
onComplete动画完成时调用的函数。易得,在我们的应用中,我们将开始下一次动画。

个人感言

其实刚开始没想做这么复杂,所以文件排的比较随意,然后就导致了后期项目完成时那副杂乱无章的样子。^_^,以后改。等我等看懂动画效果时在说,现在用的有点半懵半懂。

这篇博客写得有点乱。新手之作,就先这样吧。同上,以后改。因为不知道这个项目会不会拿来直接当我们计算机职业实践的作业。要是的话,我就彻改,连同博客。

以下是源代码地址。(我还以为csdn的下载要的积分是自己定的。等我下次彻改的时候我传到github上。现在将就一下)

https://download.csdn.net/download/qq_26136211/12011640

Html5 小游戏 俄罗斯方块的更多相关文章

  1. 推荐10款超级有趣的HTML5小游戏

    HTML5的发展速度比任何人的都想像都要更快.更加强大有效的和专业的解决方案已经被开发......甚至在游戏世界中!这里跟大家分享有10款超级趣味的HTML5游戏,希望大家能够喜欢! Kern Typ ...

  2. HTML5小游戏UI美化版

    HTML5小游戏[是男人就下一百层]UI美化版 之前写的小游戏,要么就比较简单,要么就是比较难看,或者人物本身是不会动的. 结合了其它人的经验,研究了一下精灵运动,就写一个简单的小游戏来试一下. 介绍 ...

  3. JS练习实例--编写经典小游戏俄罗斯方块

    最近在学习JavaScript,想编一些实例练练手,之前编了个贪吃蛇,但是实现时没有注意使用面向对象的思想,实现起来也比较简单所以就不总结了,今天就总结下俄罗斯方块小游戏的思路和实现吧(需要下载代码也 ...

  4. HTML5小游戏源码收藏

    html5魅族创意的贪食蛇游戏源码下载 html5网页版打砖块小游戏源码下载 html5 3D立体魔方小游戏源码下载 html5网页版飞机躲避游戏源码下载 html5三国人物连连看游戏源码下载 js ...

  5. 通通制作Html5小游戏——第二弹(仿flappy bird像素鸟)

    亲爱的博友们,我又回来啦~因为我们技术宅的思想只有技术宅懂得,好不容易写了点好玩的东西发QQ空间,结果只有11的UV,0回复....10分钟ps一个女神的素描效果发QQ空间朋友圈,一大堆回复加赞,作为 ...

  6. 菜鸟做HTML5小游戏 - 翻翻乐

    记录下开放过程.做小游戏开发,又要跨平台,flash又不支持iPhone,html5是最好的选择. 先看看最后效果: 好了,开始demo. 1.准备工作: 图片素材(省略...最后代码一起打包) 了解 ...

  7. HTML5小游戏之见缝插针

    今天给大家带来的就是一款叫做<见缝插针>的游戏.有空你就往里插,直到你无处可插!看你能过多少关! 简洁大气 黑白搭配游戏画面非常的简洁,米白色的背景中央,放置着一个不断旋转的太阳状的球体, ...

  8. HTML5小游戏【是男人就下一百层】UI美化版

    之前写的小游戏,要么就比较简单,要么就是比较难看,或者人物本身是不会动的. 结合了其它人的经验,研究了一下精灵运动,就写一个简单的小游戏来试一下. 介绍一下几个主要的类: Frame:帧的定义,主要描 ...

  9. HTML5小游戏-简单抽奖小游戏

    换了新工作以后,专注前端开发,平常空闲时间也比较多,可以多钻研一下技术,写一下博客.最近在学习canvas,参考网上的slotmachine插件,用canvas实现了一个简单抽奖小游戏.       ...

随机推荐

  1. 全面认识 RUST -- 掌控未来的雷电

    文章目录 RUST 简介 如何衡量语言的好坏? 静态语言 编译器 语言定位 代表性项目 Hello World RUST 前景 RUST 简介 Rust 是一种兼顾内存安全.高并发和稳定运行的编程语言 ...

  2. redis数据类型--hash

    /** Redis应用之Hash数据类型* 问题1:操作命令* 问题2:存储实现原理和数据结构* 问题3:应用场景* */ 先了解下什么是hash,什么是hash碰撞:hash:是包含键值对的kv的数 ...

  3. luogu P2701 [USACO5.3]巨大的牛棚Big Barn |动态规划

    题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N x N 的方格.输入数据中包括有树的 ...

  4. 【CKB.DEV 茶话会】第二期:聊聊 CKB 钱包和 Nervos DAO 全流程

    CKB.DEV 茶话会第二期:聊聊 CKB 钱包和 Nervos DAO 全流程 为了鼓励更多优秀的开发者和研究人员参与到 CKB 的开发和生态建设中去,我们希望组织一系列 CKB Developer ...

  5. UESTC1977-图书馆(AC自动机应用)

    M - 图书馆 Time Limit: 2000 MS     Memory Limit: 256 MB Submit Status 电子科技太学图书馆创建于1956年,馆舍总面积66974平方米,各 ...

  6. Ceph 块存储

    任何普通的linux主机都可以充当ceph客户机,客户机通过网络与ceph存储集群交互以存储或检索用户数据.Ceph RBD支持已经添加到linux主线内核中,从2.6.34以及以后版本开始. === ...

  7. springboot搭建一个简单的websocket的实时推送应用

    说一下实用springboot搭建一个简单的websocket 的实时推送应用 websocket是什么 WebSocket是一种在单个TCP连接上进行全双工通信的协议 我们以前用的http协议只能单 ...

  8. 网络基础TCP/IP

    TCP/IP协议族各层的作用如下 应用层 决定了向用户提供应用服务时通信的活动: 各类通用的应用服务.FTP(File Transfer Protocol,文件传输协议).DNS(Domain Nam ...

  9. Python3 并发编程1

    目录 操作系统发展 穿孔卡片 批处理 多道技术(单核) 并发与并行 进程 程序与进程 进程调度 进程的三个状态 同步和异步 阻塞与非阻塞 僵尸进程与孤儿进程 守护进程 Python中的进程操作 Pro ...

  10. 解决oracle11g数据库监听连接不上问题

    java连接数据库报错12514,无法识别监听,但是PL客户端可以连接 oracle 监听 添加ip 同时修改tnsnames.ora.listener.ora将这两个文件中HOST后面的主机都修改为 ...