实践:路径遍历(三) 迷宫探秘

本贴最后更新于 1850 天前,其中的信息可能已经时移俗易

迷宫程序 链接
迷宫生成:
image.png
解迷宫:
image.png

迷宫生成算法的可视化演示,使用 React 来实现。
迷宫的生成,涉及在图中找出生成树相关算法。
解迷宫,就是在生成的树上,进行深度遍历,寻找链接指定两个点的唯一可达路线。
以下为具体的部分关键实现代码。

import React, { Component } from 'react'; import './maze.css'; import Grid from './Grid'; class AppDemo extends Component { constructor(proprs) { super(proprs); var column = 20;//默认列数 var row = 15;//默认行数 var pixel = 35;//默认单位方格像素数 var staticMatrix = this.initStaticMatrix(column, row);//静态二维数组,第一维度是位置编号,第二维度是当下位置的邻居编号 var dynamicMatrix = this.initDynamicMatrix(column, row);//动态二维数组,第一维度是位置编号,第二维度是当下位置已连接的方向信息 var elements = this.initElements(column, row); var arr = this.initArr(column, row); var start = Math.floor(Math.random() * column * row + 1);//随机初始位置 this.state = { staticMatrix: staticMatrix, dynamicMatrix: dynamicMatrix, now: start,//当下位置* begin: start,//开始位置 end: start,//最后一个位置 column: column,//列数 row: row,//行数 timeID: 0,//定时器ID speed: 100,//速度(毫秒) speedtype: "中",//用于界面速度显示 pixel: pixel,//方格像素数 step: false,//是否参与过单步 time: 0,//用时显示 begintime: 0,//起始时间 stoptime: 0,//完成时间 reverse: [0, 3, 4, 1, 2], //用于快速反向 elements: elements,//边界元素集合 over: column * row, maxwidth: 900,//最大宽度像素数 maxheight: 600,//最大高度像素数 arr: arr,//路径元素编号信息 historyPath: [],//路径栈 findtime: 0,//用时显示 findbegintime: 0,//起始时间 findstoptime: 0,//完成时间 findtimeID: 0,//定时器ID findover: false,//寻路完毕 findStep: false,//是否参与过单步 hide: false //是否隐藏界面中的标记 } } /** * 每一步的处理算法,调用一次,迷宫界面就会向前走一步,方向是随机的 */ handle() { var elements = this.state.elements; var r = this.around(this.state.now, this.state.dynamicMatrix);//返回未涉足邻居编号集合 if (r.length < 1) {//若未涉足邻居个数小于1(即从当下位置出发已经无路可走),则随机切换到边界集合中的其他位置 if (this.state.over <= 1) { this.stop(); //this.info("迷宫已经生成完毕。"); return; } var randomNow = this.randomElement(elements); this.setState({ time: (new Date().getTime() - this.state.begintime) / 1000, now: randomNow }); } else { //方向随机1表示向上,2表示向右,3表示向下,4表示向左 var direction = this.randomDirection(r);//随机取一个方向 var next = this.state.staticMatrix[this.state.now][direction];//下一个位置编号 if (this.around(next, this.state.dynamicMatrix).length >= 2) {//如果下一个位置的未涉足邻居个数大于等于2,则标记为边界。 elements[next] = 1; } var dynamicMatrix = this.state.dynamicMatrix;//动态生成的“树” this.connect(this.state.now, direction, next, dynamicMatrix);//连接now和next this.setState({ time: (new Date().getTime() - this.state.begintime) / 1000, now: next, elements: this.freshElements(elements, next, dynamicMatrix), dynamicMatrix: dynamicMatrix, over: this.state.over - 1 }); } } findPath() { if (this.state.findover === false && this.state.over <= 1) { var historyPath = this.state.historyPath;//历史路径 var dynamicMatrix = this.state.dynamicMatrix; var arr = this.state.arr;//路径编号 var staticMatrix = this.state.staticMatrix; if (historyPath.length === 0) { historyPath.push(dynamicMatrix[1].concat()); //arr[historyPath[historyPath.length - 1][0]][] = 1; } var nowRow = historyPath[historyPath.length - 1][0];//获取当下的位置编号 var b = false; for (var i = 1; i <= 4; i++) { var p = historyPath[historyPath.length - 1][i]; if (p === 1) { var next = staticMatrix[nowRow][i]; historyPath.push(dynamicMatrix[next].concat()); historyPath[historyPath.length - 1][this.state.reverse[i]] = 0; arr[next][this.state.reverse[i]] = 1; arr[nowRow][i] = 1; this.setState({ findtime: (new Date().getTime() - this.state.findbegintime) / 1000, historyPath: historyPath, arr: arr }); if (next === this.state.column * this.state.row) { this.findStop(); this.setState({ findover: true }); //this.info("迷宫路径已找到(暂时只支持从左上到右下)。"); return; } b = true; break; } } if (!b) {//如果无路可走 //判断当下路径(未退步之前)是否包含于历史记录。 var nown = historyPath[historyPath.length - 1][0]; var last = historyPath[historyPath.length - 2][0]; arr[nown] = [nown,0,0,0,0]; historyPath.pop(); for (var j = 1; j <= 4; j++) { var p2 = historyPath[historyPath.length - 1][j]; if (p2 === 1) { arr[last][j] = 0; historyPath[historyPath.length - 1][j] = 0; this.setState({ findtime: (new Date().getTime() - this.state.findbegintime) / 1000, historyPath: historyPath, arr: arr }); break; } } } } else { this.findStop(); } } /** * 启动解迷宫程序 */ findStart() { if (this.state.over <= 1) {//若迷宫已经生成完毕,才可以解迷宫 var findtimeID = this.state.findtimeID; if (findtimeID === 0) {//若 当下定时器不为0,则启动新定时器(防止重复启动多个定时器) findtimeID = setInterval( () => this.findPath(), this.state.speed ); this.setState({ findbegintime: new Date().getTime() - this.state.findtime * 1000, findtimeID: findtimeID, now: 0 }); } }else{ this.info("需要先生成迷宫,才能解迷宫的!笨蛋"); } } findStop() { var findtimeID = this.state.findtimeID; if (findtimeID !== 0) { clearInterval(findtimeID); this.setState({ findtimeID: 0 }); } } findStep() { this.findStop(); this.findPath(); this.setState({ findStep: true }); } hide(){ this.setState({ hide: !this.state.hide }); } render() { return ( <div className="maze"> <div className="aaa"> <Grid pixel={this.state.pixel} width={this.state.column} height={this.state.row} dynamicMatrix={this.state.dynamicMatrix} now={this.state.now} elements={this.state.elements} begin={this.state.begin} end={this.state.end} arr={this.state.arr} hide={this.state.hide} /> </div> <div className="bbb"> <div className="control navbar navbar-default"> <span className="title">生成迷宫:(用时{this.state.step ? "单步参与后不再计时" : (this.state.time + "s")})</span><br /> <span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.start()}>开始</button><span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.stop()}>暂停</button><span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.start()}>继续</button><span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.step()}>单步</button><span >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </div> <div className="control navbar navbar-default"> <span className="title">解迷宫:(用时{this.state.findStep ? "单步参与后不再计时" : (this.state.findtime + "s")})<span >&nbsp;&nbsp;&nbsp;</span>{this.state.findover?("找到,路径长度为:"+this.state.historyPath.length)+"":"迷宫入口为左上角,出口为右下角。"}</span><br /> <span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.findStart()}>开始</button><span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.findStop()}>暂停</button><span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.findStart()}>继续</button><span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.findStep()}>单步</button><span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.resetFind()}>清除</button> </div> <div className="control navbar navbar-default"> <span className="title">速度:{this.state.speedtype}</span><br /> <span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" type="button" onClick={() => this.speed(1000)}>极慢</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" type="button" onClick={() => this.speed(500)}>慢</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" type="button" onClick={() => this.speed(100)}>中</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" type="button" onClick={() => this.speed(50)}>快</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" type="button" onClick={() => this.speed(10)}>极���</button> </div> <div className="control navbar navbar-default"> <span className="title">列数:{this.state.column}</span><br /> <span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.addwidth(1)}>列+1</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.addwidth(-1)}>列-1</button> <span >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.addwidth(5)}>列+5</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.addwidth(-5)}>列-5</button><br /> </div> <div className="control navbar navbar-default"> <span className="title">行数:{this.state.row}</span><br /> <span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.addheight(1)}>行+1</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.addheight(-1)}>行-1</button> <span >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.addheight(5)}>行+5</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.addheight(-5)}>行-5</button><br /> </div> <div className="control navbar navbar-default"> <span className="title">大小:{this.state.column * this.state.pixel}px&nbsp;:&nbsp;{this.state.row * this.state.pixel}px</span><br /> <span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.big(1)}>放大+1</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.big(-1)}>缩小-1</button> <span >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.big(5)}>放大+5</button><span >&nbsp;&nbsp;&nbsp;</span> <button className="btn btn-primary navbar-btn" style={{ width: "80px" }} type="button" onClick={() => this.big(-5)}>缩小-5</button><br /> </div> <div className="control navbar navbar-default"> <span className="title">其他:</span><br /> <span >&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.hide()}>{this.state.hide?"显示标记":"隐藏标记"}</button><span >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <button type="button" className="btn btn-primary navbar-btn" onClick={() => this.resetAll()}>全部重置</button> </div> </div> </div > ) } /** * 连接now和next两个位置 * @param {*} now * @param {*} direction * @param {*} next * @param {*} dynamicMatrix */ connect(now, direction, next, dynamicMatrix) { dynamicMatrix[now][direction] = 1;//连接下一个位置 dynamicMatrix[next][this.state.reverse[direction]] = 1;//连接下一个位置 } /** * 从边界集合中随机选择一个返回 * @param {} elements */ randomElement(elements) { var u = this.state.column * this.state.row var n = Math.floor(Math.random() * u); var i = 0; while (elements[n] !== 1) { i++; n++; if (n > u) { n = 1; } if (i > u) { n = 0; break; } } return n; } /** * 初始化StaticMatrix * @param {*} width * @param {*} height */ initStaticMatrix(width, height) { var matrix = [[0, 1, 2, 3, 4]]; for (var numb = 1; numb <= width * height; numb++) { var up = numb > width ? numb - width : 0; var right = (numb % width) !== 0 ? numb + 1 : 0; var down = numb <= width * (height - 1) ? numb + width : 0; var left = ((numb - 1) % width) !== 0 ? numb - 1 : 0; var arr = [numb]; arr.push(up); arr.push(right); arr.push(down); arr.push(left); matrix.push(arr); } return matrix; } /** * 初始化DynamicMatrix * @param {*} width * @param {*} height */ initDynamicMatrix(width, height) { var dynamicMatrix = [[0, 1, 2, 3, 4]]; for (var numb = 1; numb <= width * height; numb++) { var up = 0; var right = 0; var down = 0; var left = 0; var arr = [numb]; arr.push(up); arr.push(right); arr.push(down); arr.push(left); dynamicMatrix.push(arr); } return dynamicMatrix; } initArr(width, height) { var dynamicMatrix = [[0, 1, 2, 3, 4]]; for (var numb = 1; numb <= width * height; numb++) { var up = 0; var right = 0; var down = 0; var left = 0; var arr = [numb]; arr.push(up); arr.push(right); arr.push(down); arr.push(left); dynamicMatrix.push(arr); } return dynamicMatrix; } /** * 初始化Elements边界集合 * @param {*} column * @param {*} row */ initElements(column, row) { var arr = new Array(column * row + 1); for (var i = 0; i < arr.length; i++) { arr[i] = 0; } return arr; } /** * 返回未涉足邻居编号集合 * 参数new,是当下位置的编号 */ around(now, dynamicMatrix) { var r = []; for (var j = 1; j <= 4; j++) {//每个位置周边共四个“邻居” var runod = this.state.staticMatrix[now][j];//其中一个邻居 //判断“邻居”是否已经被涉足,若没有,则将此邻居方向编号加入将要返回的集合中 if (runod !== 0 && (dynamicMatrix[runod][1] === 0 && dynamicMatrix[runod][2] === 0 && dynamicMatrix[runod][3] === 0 && dynamicMatrix[runod][4] === 0)) { r.push(j); } } return r;//返回未涉足邻居方向编号集合 } /** * 从邻居中随机选出一个作为下一个位置 * @param {*} r */ randomDirection(r) { if (r.length === 1) { return r[r.length - 1]; } return r[Math.floor(Math.random() * r.length)]; } /** * 刷新边界集合,(每前进一步,整个盘面唯有一个位置有所改变,所以只扫面更新此位置四周即可) * @param {*} elements * @param {*} next * @param {*} dynamicMatrix */ freshElements(elements, next, dynamicMatrix) { for (var n = 1; n <= 4; n++) { var runod = this.state.staticMatrix[next][n];//其中一个邻居 //判断“邻居”是否已经被涉足,若没有,则将此邻居编号加入将要返回的集合中 if (elements[runod] !== 0 && this.around(runod, dynamicMatrix).length === 0) {//如果elements[n]周围没有未涉足区域,则从边缘集合中去掉 elements[runod] = 0; } } return elements; } /** * 添加列数,n为添加的列数 * @param {*} n */ addwidth(n) { this.stop(); var column = this.state.column; column = column + n; if (column > 0 && column * this.state.pixel <= this.state.maxwidth) { var staticMatrix = this.initStaticMatrix(column, this.state.row); var dynamicMatrix = this.initDynamicMatrix(column, this.state.row); var elements = this.initElements(column, this.state.row); var arr = this.initArr(column, this.state.row); var start = Math.floor(Math.random() * column * this.state.row + 1); this.setState({ staticMatrix: staticMatrix, dynamicMatrix: dynamicMatrix, begin: start, now: start, column: column, time: 0, elements: elements, over: column * this.state.row, arr: arr, historyPath: [], findtime: 0, findover: false }); } else { var maxColumn = Math.floor(this.state.maxwidth / this.state.pixel); var staticMatrix1 = this.initStaticMatrix(maxColumn, this.state.row); var dynamicMatrix1 = this.initDynamicMatrix(maxColumn, this.state.row); var elements1 = this.initElements(maxColumn, this.state.row); var arr1 = this.initArr(maxColumn, this.state.row); var newstart = Math.floor(Math.random() * maxColumn * this.state.row + 1); this.setState({ staticMatrix: staticMatrix1, dynamicMatrix: dynamicMatrix1, begin: newstart, now: newstart, column: maxColumn, time: 0, elements: elements1, over: maxColumn * this.state.row, arr: arr1, historyPath: [], findtime: 0, findover: false }); } } /** * 添加行数,n为添加的行数 * @param {*} n */ addheight(n) { this.stop(); var row = this.state.row; row = row + n; if (row > 0 && row * this.state.pixel <= this.state.maxheight) { var staticMatrix = this.initStaticMatrix(this.state.column, row); var dynamicMatrix = this.initDynamicMatrix(this.state.column, row); var elements = this.initElements(this.state.column, row); var arr = this.initArr(this.state.column, row); var start = Math.floor(Math.random() * this.state.column * row + 1); this.setState({ staticMatrix: staticMatrix, dynamicMatrix: dynamicMatrix, begin: start, now: start, row: row, time: 0, elements: elements, over: this.state.column * row, arr: arr, historyPath: [], findtime: 0, findover: false }); } else { var maxRow = Math.floor(this.state.maxheight / this.state.pixel); var staticMatrix1 = this.initStaticMatrix(this.state.column, maxRow); var dynamicMatrix1 = this.initDynamicMatrix(this.state.column, maxRow); var elements1 = this.initElements(this.state.column, maxRow); var arr1 = this.initArr(this.state.column, maxRow); var newstart = Math.floor(Math.random() * this.state.column * maxRow + 1); this.setState({ staticMatrix: staticMatrix1, dynamicMatrix: dynamicMatrix1, begin: newstart, now: newstart, time: 0, row: maxRow, elements: elements1, over: this.state.column * maxRow, arr: arr1, historyPath: [], findtime: 0, findover: false }); } } /** * 缩放界面大小,n为每个单位方格改变的像素数 * @param {*} n */ big(n) { var pixel = this.state.pixel; pixel = pixel + n; if (pixel >= 5 && ((pixel * this.state.column <= this.state.maxwidth) && (pixel * this.state.row <= this.state.maxheight))) { this.setState({ pixel: pixel }); return; } if(pixel < 5 ){ this.info("已经最小,再小你就看不见了,你以为你是显微镜呀!"); this.setState({ pixel: 5 }); }else { this.info("不能再大了,笨蛋"); this.setState({ pixel: Math.floor((pixel * this.state.column / this.state.maxwidth > pixel * this.state.row / this.state.maxheight) ? (this.state.maxwidth / this.state.column) : (this.state.maxheight / this.state.row)) }); } } /** * 重置应用,使其除行列和大小外,其他因素设置成初始状态 */ resetAll() { this.stop(); var staticMatrix = this.initStaticMatrix(this.state.column, this.state.row); var dynamicMatrix = this.initDynamicMatrix(this.state.column, this.state.row); var elements = this.initElements(this.state.column, this.state.row); var arr = this.initArr(this.state.column, this.state.row); var start = Math.floor(Math.random() * this.state.column * this.state.row + 1); this.setState({ staticMatrix: staticMatrix, dynamicMatrix: dynamicMatrix, begin: start, now: start, time: 0, elements: elements, over: this.state.column * this.state.row, arr: arr,//路径元素编号信息 historyPath: [],//路径栈 findtime: 0,//用时显示 findbegintime: 0,//起始时间 findstoptime: 0,//完成时间 findtimeID: 0,//定时器ID findover: false,//寻路完毕 findStep: false,//是否参与过单步 hide: false //是否隐藏界面中的标记 }); } /** * 重置应用,使其除行列和大小外,其他因素设置成初始状态 */ resetFind() { this.findStop(); var arr = this.initArr(this.state.column, this.state.row); this.setState({ arr: arr,//路径元素编号信息 historyPath: [],//路径栈 findtime: 0,//用时显示 findbegintime: 0,//起始时间 findstoptime: 0,//完成时间 findtimeID: 0,//定时器ID findover: false,//寻路完毕 findStep: false,//是否参与过单步 hide: false //是否隐藏界面中的标记 }); } /** * 单步 */ step() { this.stop(); this.handle(); this.setState({ step: true }); } /** * 开始 */ start() { var timeID = this.state.timeID; if (timeID === 0) { timeID = setInterval( () => this.handle(), this.state.speed ); this.setState({ begintime: new Date().getTime() - this.state.time * 1000, timeID: timeID }); } } /** * 暂停 */ stop() { var timeID = this.state.timeID; if (timeID !== 0) { clearInterval(timeID); this.setState({ timeID: 0 }); } } /** * 改变速度,n为新的时间间隔,单位ms,每隔n ms时间,定时器调用一次相关方法 * @param {*} n */ speed(n) { var timeID = this.state.timeID; if (timeID !== 0) { clearInterval(timeID); timeID = 0; timeID = setInterval( () => this.handle(), n ); } var findtimeID = this.state.findtimeID; if (findtimeID !== 0) { clearInterval(findtimeID); findtimeID = 0; findtimeID = setInterval( () => this.findPath(), n ); } var speedtype = ""; if (n === 10) { speedtype = "极快"; } if (n === 50) { speedtype = "快"; } if (n === 100) { speedtype = "中"; } if (n === 500) { speedtype = "慢"; } if (n === 1000) { speedtype = "极慢"; } this.setState({ timeID: timeID, findtimeID: findtimeID, speed: n, speedtype: speedtype }); } info(info){ alert(info); } } export default AppDemo;

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    21 引用 • 31 回帖 • 1 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 5 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 645 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    36 引用 • 200 回帖 • 31 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 555 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    167 引用 • 408 回帖 • 490 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 191 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 7 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 654 关注
  • CodeMirror
    2 引用 • 17 回帖 • 166 关注
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 606 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 3 关注
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 26 关注
  • Electron

    Electron 基于 Chromium 和 Node.js,让你可以使用 HTML、CSS 和 JavaScript 构建应用。它是一个由 GitHub 及众多贡献者组成的活跃社区共同维护的开源项目,兼容 Mac、Windows 和 Linux,它构建的应用可在这三个操作系统上面运行。

    15 引用 • 136 回帖 • 1 关注
  • 电影

    这是一个不能说的秘密。

    122 引用 • 608 回帖
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 613 关注
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖 • 5 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    209 引用 • 2040 回帖
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    291 引用 • 4495 回帖 • 661 关注
  • RemNote
    2 引用 • 16 回帖 • 22 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 438 关注
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    44 引用 • 208 回帖
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    554 引用 • 675 回帖
  • 笔记

    好记性不如烂笔头。

    310 引用 • 794 回帖 • 1 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 677 关注