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

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

迷宫程序 链接
迷宫生成:
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;

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖 • 8 关注
  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    116 引用 • 54 回帖 • 4 关注
  • 生活

    生活是指人类生存过程中的各项活动的总和,范畴较广,一般指为幸福的意义而存在。生活实际上是对人生的一种诠释。生活包括人类在社会中与自己息息相关的日常活动和心理影射。

    230 引用 • 1454 回帖
  • GitHub

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

    210 引用 • 2040 回帖
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    159 引用 • 298 回帖
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 442 关注
  • Word
    13 引用 • 40 回帖
  • GitLab

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

    46 引用 • 72 回帖 • 2 关注
  • 七牛云

    七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化 PaaS 服务。围绕富媒体场景,七牛先后推出了对象存储,融合 CDN 加速,数据通用处理,内容反垃圾服务,以及直播云服务等。

    28 引用 • 226 回帖 • 135 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1440 引用 • 10067 回帖 • 492 关注
  • jQuery

    jQuery 是一套跨浏览器的 JavaScript 库,强化 HTML 与 JavaScript 之间的操作。由 John Resig 在 2006 年 1 月的 BarCamp NYC 上释出第一个版本。全球约有 28% 的网站使用 jQuery,是非常受欢迎的 JavaScript 库。

    63 引用 • 134 回帖 • 734 关注
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖 • 3 关注
  • Excel
    31 引用 • 28 回帖
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    200 引用 • 120 回帖
  • Follow
    4 引用 • 12 回帖 • 8 关注
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 143 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    133 引用 • 891 回帖 • 1 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    132 引用 • 1115 回帖 • 120 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖 • 1 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    428 引用 • 1250 回帖 • 596 关注
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    325 引用 • 1395 回帖 • 1 关注
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 100 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    151 引用 • 257 回帖
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 83 关注
  • Latke

    Latke 是一款以 JSON 为主的 Java Web 框架。

    71 引用 • 535 回帖 • 820 关注