Advertisement
Guest User

Reasoning Realm v0.2.0 for EVERYONE! even you! yoooou!!!! :D

a guest
Aug 1st, 2016
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 56.89 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <!-- blah 2016 -->
  3. <html>
  4. <head>
  5. <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
  6. <style>
  7. canvas { /* Credit: http://stackoverflow.com/questions/7615009/disable-interpolation-when-scaling-a-canvas */
  8. image-rendering: optimizeSpeed;
  9. image-rendering: -moz-crisp-edges;
  10. image-rendering: -webkit-optimize-contrast;
  11. image-rendering: -o-crisp-edges;
  12. image-rendering: pixelated;
  13. -ms-interpolation-mode: nearest-neighbor;
  14. }
  15. .selMenuItem:hover {
  16. background-color:rgba(255,255,255,0.1);
  17. }
  18. .selMenuItemHighlighted {
  19. background-color:white;
  20. color:black;
  21. }
  22. .button {
  23. background-color:#111111;
  24. color:white;
  25. cursor:pointer;
  26. border:1px solid black;
  27. border-radius:4px;
  28. padding:0px 4px 0px 4px;
  29. }
  30. .button:hover {
  31. background-color:white;
  32. color:#111;
  33. }
  34. .button:active {
  35. background-color:#555;
  36. color:#ccc;
  37. }
  38. .number {
  39. font-family:consolas,monospace;
  40. }
  41. body { /* Credit: http://stackoverflow.com/questions/6900124/how-to-make-certain-text-not-selectable-with-css */
  42. -webkit-user-select: none;
  43. -moz-user-select: none;
  44. -ms-user-select: none;
  45. color:white;
  46. font-family:sans-serif;
  47. font-size:12px;
  48. background-color:black;
  49. margin:0;
  50. }
  51. html, body {
  52. height: 100%;
  53. }
  54. input {
  55. background-color:#000000;
  56. color:white;
  57. border:1px solid #ffff00;
  58. border-radius:3px;
  59. font-family:consolas,monospace;
  60. }
  61. input:hover {
  62. background-color:#111111;
  63. }
  64. textarea {
  65. background-color:#000000;
  66. color:white;
  67. border:1px solid #ffff00;
  68. border-radius:3px;
  69. font-family:consolas,monospace;
  70. font-size: 12px;
  71. }
  72. textarea:hover {
  73. background-color:#111111;
  74. }
  75. a {
  76. color:#ffffff;
  77. }
  78. h1 {
  79. text-align:center;
  80. }
  81. h2 {
  82. text-align:center;
  83. }
  84. h3 {
  85. margin:0;
  86. margin-top:4px;
  87. }
  88. p.date {
  89. margin:0;
  90. font-size:8px;
  91. }
  92. .changelist {
  93. margin:0;
  94. }
  95. .blah {
  96. font-weight:bold;
  97. font-size:55px;
  98. }
  99. .blah:hover {
  100. animation: pulse 0.5s infinite;
  101. color:rgba(0,0,0,0);
  102. }
  103. @keyframes pulse {
  104. 0% {
  105. text-shadow:20px 20px 5px #ff0;
  106. }
  107. 10% {
  108. text-shadow:10px -30px 15px #f0f;
  109. }
  110. 20% {
  111. text-shadow:2px 5px 10px #fff;
  112. }
  113. 30% {
  114. text-shadow:30px 300px 0px #777;
  115. }
  116. 50% {
  117. text-shadow:1px 1px 1px #f00;
  118. }
  119. 100% {
  120. text-shadow:20px 20px 5px #ff0;
  121. }
  122. }
  123. </style>
  124. <title>Reasoning Realm</title>
  125. <script>
  126. var worldX = 64; //Width of the world.
  127. var worldY = 64; //Height of the world.
  128. var cellList = []; //List of every cell in the world.
  129. var colours = []; //Colour scheme. Modified by setRule().
  130. var names = []; //Names belonging to those colours.
  131. var running = true; //You can pause the simulation using this.
  132. var zoom = 8; //each cell is zoom pixels squared
  133. var canvasHeight = 512; //Height of the canvas. So you can resize it, otherwise this variable would be useless
  134. var canvasWidth = 512; //See canvasHeight.
  135. var drawType = 1; //The value you can set pixels to with the mouse.
  136. var mouseIsDown = false; //Used for clicking and dragging.
  137. var cameraPanX = 0; //for panning the camera. What an insightful comment I know
  138. var cameraPanY = 0; //It's measured in pixels.
  139. var eorc = true; //This variable is used by the resize function. It is whether to expand or contract the world. It's global because it can get modified by a button
  140. var dir = 0; //Also used by the resize function. The direction of expansion.
  141. var rectPosY = 0; //Selection location. This is the top left corner
  142. var rectPosX = 0;
  143. var rectSizeY = 1; //Dimensions of the selection. going down right
  144. var rectSizeX = 1;
  145. var rectDragging = false; //Whether or not the player is dragging the selection, or if they're first making it
  146. var rectDragX = 8; //For when you drag the selection; it's the location of the cursor relative to the top left corner of the selection.
  147. var rectDragY = 8;
  148. var rectCellList = [[0,0],[0,0]];
  149. var rectExists = false;
  150. var clipboard = [ //For copy/paste functionality on the selection tool. nothing to see here move along
  151. [1,0,1,0,1,1,1,0,0,1,1,0,0,0,1,0,0,1,1,0], //The clipboard doesn't need length or height variables cause we can just use clipboard.length for Y and clipboard[0].length for X
  152. [1,1,1,0,0,1,0,0,0,1,0,1,0,1,1,1,0,1,0,1],
  153. [1,0,1,0,1,1,1,0,0,1,1,0,0,1,0,1,0,1,0,1]];
  154. var appHeight = 512; //The height of the entire app, in pixels.
  155. var appWidth = 512; //See appHeight
  156. var panning = [false,false,false,false]; //It's an array of the four directions. If the value for left is true, the camera will be panning to the left. More than one can be true at the same time. Allows fluid panning.
  157. var transitions = [ //Transition table. Initialised, as you can see, to B3/S23. This obviously supports generations rules if you try, but I use a different function because it's faster.
  158. [0,0,0,1,0,0,0,0,0],
  159. [0,0,1,1,0,0,0,0,0]];
  160. var speedDT = 1; //Optimal delta time (amount of time between frames) multiplied by 15ms
  161. var speedMult = 1; //Amount of iterations per frame.
  162. var tickCount = 0; //Used internally to work with speedDT. Like, if speedDT == 2, it'll use this to only simulate every other frame
  163. var rule = ""; //Used for the 'rule = whatever' part of RLE savecodes
  164. var pauselock = false; //dan
  165. var sparse = [];
  166. var nextSparse = [];
  167. var difference = [];
  168. var algorithm = 1; //0 is sparse algorithm, 1 is brute force
  169. var generation = 0; //Amount of generations since the pattern was loaded.
  170. var gpscount = 0;
  171. //That was the variables. Now we start listing out functions. The 'meat' of the script.
  172.  
  173. //Create the world.
  174. for (y=0; y < worldY; y++){
  175. cellList[y] = [];
  176. for (x=0; x < worldX; x++){
  177. cellList[y][x] = 0;
  178. }
  179. }
  180.  
  181. function drawWorld(){ //Render the world. never use this unless there's some clear reason to, because it draws every cell in the world.
  182. drawEmpty();
  183. for (y=0; y < worldY; y++){
  184. for (x=0; x < worldX; x++){
  185. if(cellList[y][x] > 0){
  186. drawCellAt(x,y);
  187. }
  188. }
  189. }
  190. }
  191.  
  192. function drawCell(x,y,type){ //Use this if you already know what the cell's state will be (faster than having this look it up when you already know)
  193. d[0] = colours[type][0];
  194. d[1] = colours[type][1];
  195. d[2] = colours[type][2];
  196. canvas.putImageData(id,x,y);
  197. }
  198.  
  199. function drawCellAt(x,y){ //Otherwise use this
  200. drawCell(x,y,cellList[y][x]);
  201. }
  202.  
  203. function getCell(x,y){ //Is the cell at [x,y] within the field? if so return its type
  204. if (x > -1 && x < worldX && y > -1 && y < worldY){
  205. return cellList[y][x];
  206. } else {
  207. return false;
  208. }
  209. }
  210.  
  211. function vonNeumannNeighbours(x,y,type){ //Returns amount of cells equal to type within the Von Neumann neighbourhood of x,y
  212. var count=0;
  213. if(cellList[y][x-1] == type){
  214. count++;
  215. };
  216. if(cellList[y-1] != undefined && cellList[y-1][x] == type){
  217. count++;
  218. };
  219. if(cellList[y][x+1] == type){
  220. count++;
  221. };
  222. if(cellList[y+1] != undefined && cellList[y+1][x] == type){
  223. count++;
  224. };
  225. return count;
  226. }
  227.  
  228. function mooreNeighbours(x,y,type){ //Returns amount of cells equal to type within the Von Neumann neighbourhood of x,y
  229. var count=0;
  230. var bottom = cellList[y+1] != undefined;
  231. var top = cellList[y-1] != undefined;
  232. if(cellList[y][x-1] == type){
  233. count++;
  234. };
  235. if(top && cellList[y-1][x] == type){
  236. count++;
  237. };
  238. if(cellList[y][x+1] == type){
  239. count++;
  240. };
  241. if(bottom && cellList[y+1][x] == type){
  242. count++;
  243. };
  244. if(top && cellList[y-1][x-1] == type){
  245. count++;
  246. };
  247. if(bottom && cellList[y+1][x-1] == type){
  248. count++;
  249. };
  250. if(top && cellList[y-1][x+1] == type){
  251. count++;
  252. };
  253. if(bottom && cellList[y+1][x+1] == type){
  254. count++;
  255. };
  256. return count;
  257. }
  258.  
  259. function putCell(x,y,type){ //This is for things where the player is editing the canvas.
  260. drawCell(x,y,type);
  261. cellList[y][x] = type;
  262. if(algorithm == 0){
  263. if(!inSparse(x,y)){
  264. sparse.push(y,x);
  265. }
  266. if(!inSparse(x-1,y)){
  267. sparse.push(y,x-1);
  268. }
  269. if(!inSparse(x+1,y)){
  270. sparse.push(y,x+1);
  271. }
  272. if(!inSparse(x,y-1)){
  273. sparse.push(y-1,x);
  274. }
  275. if(!inSparse(x+1,y-1)){
  276. sparse.push(y-1,x+1);
  277. }
  278. if(!inSparse(x-1,y-1)){
  279. sparse.push(y-1,x-1);
  280. }
  281. if(!inSparse(x,y+1)){
  282. sparse.push(y+1,x);
  283. }
  284. if(!inSparse(x+1,y+1)){
  285. sparse.push(y+1,x+1);
  286. }
  287. if(!inSparse(x-1,y+1)){
  288. sparse.push(y+1,x-1);
  289. }
  290. }
  291. }
  292.  
  293. function setCell(x,y,type){ //This is for the tick function. It's efficient.
  294. drawCell(x,y,type);
  295. difference.push(y,x,type);
  296. if(algorithm == 0){
  297. padSparse(x,y);
  298. }
  299. }
  300.  
  301. function padSparseMoore(x,y){
  302. if(!inSparse(x,y)){
  303. nextSparse.push(y,x);
  304. }
  305. if(!inSparse(x-1,y)){
  306. nextSparse.push(y,x-1);
  307. }
  308. if(!inSparse(x+1,y)){
  309. nextSparse.push(y,x+1);
  310. }
  311. if(!inSparse(x,y-1)){
  312. nextSparse.push(y-1,x);
  313. }
  314. if(!inSparse(x+1,y-1)){
  315. nextSparse.push(y-1,x+1);
  316. }
  317. if(!inSparse(x-1,y-1)){
  318. nextSparse.push(y-1,x-1);
  319. }
  320. if(!inSparse(x,y+1)){
  321. nextSparse.push(y+1,x);
  322. }
  323. if(!inSparse(x+1,y+1)){
  324. nextSparse.push(y+1,x+1);
  325. }
  326. if(!inSparse(x-1,y+1)){
  327. nextSparse.push(y+1,x-1);
  328. }
  329. }
  330.  
  331. function padSparseJvN(x,y){
  332. if(!inSparse(x,y)){
  333. nextSparse.push(y,x);
  334. }
  335. if(!inSparse(x-1,y)){
  336. nextSparse.push(y,x-1);
  337. }
  338. if(!inSparse(x+1,y)){
  339. nextSparse.push(y,x+1);
  340. }
  341. if(!inSparse(x,y-1)){
  342. nextSparse.push(y-1,x);
  343. }
  344. if(!inSparse(x,y+1)){
  345. nextSparse.push(y+1,x);
  346. }
  347. }
  348.  
  349. function applyDifference(){
  350. for(i=0;i<difference.length;i+=3){
  351. cellList[difference[i]][difference[i+1]] = difference[i+2];
  352. }
  353. }
  354.  
  355. function inSparse(x,y){
  356. for(ib=0;ib<nextSparse.length;ib+=2){
  357. if(nextSparse[ib] == y && nextSparse[ib+1] == x){
  358. return true;
  359. }
  360. }
  361. return false;
  362. }
  363.  
  364. function fillSparse(){
  365. for(y=0;y<worldY;y++){
  366. for(x=0;x<worldX;x++){
  367. sparse.push(y,x);
  368. }
  369. }
  370. }
  371.  
  372. function transLife(x,y){
  373. return transitions[cellList[y][x]][mooreNeighbours(x,y,1)];
  374. }
  375.  
  376. function transGenerations(x,y){
  377. cell = cellList[y][x];
  378. if(cell<2){
  379. return transitions[cell][mooreNeighbours(x,y,1)];
  380. } else if(cell==colours.length-1) {
  381. return 0;
  382. } else {
  383. return cell+1;
  384. }
  385. }
  386.  
  387. function transLL(x,y){ //Logic land transition function
  388. cell = cellList[y][x];
  389. if(cell == 0){ //Empty Space
  390. //Do nothing. Faster than running through all the other conditions, even if it requires an empty block.
  391. } else if(cell == 1 && (vonNeumannNeighbours(x,y,2) > 0 || vonNeumannNeighbours(x,y,16) > 0 )){ //Inactive Wire
  392. return 2;
  393. } else if(cell == 2 && (vonNeumannNeighbours(x,y,3) > 0 || vonNeumannNeighbours(x,y,10))){ //Active Wire
  394. return 3;
  395. } else if(cell == 3){ //Inhibited Wire
  396. return 1;
  397. } else if(cell == 4){ //Cross Over. This one is complex and inefficient, so don't use Crossovers to speed up wires, cause it slows the simulation down in the long term.
  398. if(x>0 && x < worldX-1 && y>0 && y < worldY-1 ){
  399. friends = [cellList[y][x-1], cellList[y-1][x], cellList[y][x+1], cellList[y+1][x]];
  400. friendLocs = [y,x-1,y-1,x,y,x+1,y+1,x];
  401. for(i=0;i<4;i++){
  402. if(friends[i] == 2 && friends[(i+2)%4] == 1){
  403. setCell(friendLocs[((i+2)%4)*2+1],friendLocs[((i+2)%4)*2],2);
  404. }
  405. if(friends[i] == 3 && friends[(i+2)%4] == 2){
  406. setCell(friendLocs[((i+2)%4)*2+1],friendLocs[((i+2)%4)*2],3);
  407. }
  408. }
  409. }
  410. return 4;
  411. } else if(cell > 4 && cell < 9 && vonNeumannNeighbours(x,y,2) > 0){ //Inactive gates
  412. return cell+6;
  413. } else if(cell > 10 && cell < 15 && vonNeumannNeighbours(x,y,2) == 0){ //Active gates
  414. return cell-6;
  415. } else if(cell == 15 && vonNeumannNeighbours(x,y,3) > 0){ //Active T-flip flop
  416. return 9;
  417. } else if(cell == 9 && vonNeumannNeighbours(x,y,3) > 0){ //Inactive T-flip flop
  418. return 15;
  419. } else if(cell == 10 || cell == 16){ //Gate output
  420. if(vonNeumannNeighbours(x,y,11) > 0 || vonNeumannNeighbours(x,y,5) > 0){ //NOR
  421. if(vonNeumannNeighbours(x,y,11) == 0){
  422. return 16;
  423. } else {
  424. return 10;
  425. }
  426. } else if(vonNeumannNeighbours(x,y,12) > 0 || vonNeumannNeighbours(x,y,6) > 0){ //OR
  427. if(vonNeumannNeighbours(x,y,12) > 0){
  428. return 16;
  429. } else {
  430. return 10;
  431. }
  432. } else if(vonNeumannNeighbours(x,y,13) > 0 || vonNeumannNeighbours(x,y,7) > 0){ //XOR
  433. if(vonNeumannNeighbours(x,y,13) == 1){
  434. return 16;
  435. } else {
  436. return 10;
  437. }
  438. } else if(vonNeumannNeighbours(x,y,14) > 0 || vonNeumannNeighbours(x,y,8) > 0){ //AND
  439. if(vonNeumannNeighbours(x,y,8) == 0){
  440. return 16;
  441. } else {
  442. return 10;
  443. }
  444. } else if(vonNeumannNeighbours(x,y,15) > 0 || vonNeumannNeighbours(x,y,9) > 0){ //T flip flop
  445. if(vonNeumannNeighbours(x,y,9) > 0){
  446. return 10;
  447. } else {
  448. return 16;
  449. }
  450. }
  451. }
  452. return cell;
  453. }
  454.  
  455. var transFunc = transLL;
  456. function tick(){
  457. if(!pauselock){
  458. for(ilk=0;ilk<speedMult;ilk++){
  459. generation++;
  460. document.getElementById("genNum").innerHTML = generation;
  461. difference = [];
  462. if(algorithm == 0){
  463. nextSparse = [];
  464. for(il=0;il<sparse.length;il+=2){
  465. var y = sparse[il];
  466. var x = sparse[il+1];
  467. if(y>-1 && y<worldY && x>-1 && x<worldX){
  468. var newCell = transFunc(x,y);
  469. if(newCell != cellList[y][x]){
  470. setCell(x,y,newCell);
  471. }
  472. }
  473. }
  474. sparse = nextSparse.slice();
  475.  
  476. } else if(algorithm == 1){
  477. for(y=0;y<worldY;y++){
  478. for(x=0;x<worldX;x++){
  479. var newCell = transFunc(x,y);
  480. if(newCell != cellList[y][x]){
  481. setCell(x,y,newCell);
  482. }
  483. }
  484. }
  485. }
  486. applyDifference();
  487. }
  488. }
  489. }
  490.  
  491. function mouseDown(event){ //Event called when the mouse gets first pressed
  492. mouseIsDown = true;
  493. cellx = Math.floor((event.clientX - crect.left)/zoom);
  494. celly = Math.floor((event.clientY - crect.top)/zoom);
  495. if(drawType == -1){
  496. if(cellx >= rectPosX && celly >= rectPosY && cellx <= rectPosX+rectSizeX && celly <= rectPosY+rectSizeY && rectExists){ //If you clicked on the selection
  497. rectDragging = true;
  498. rectDragX = cellx-rectPosX;
  499. rectDragY = celly-rectPosY;
  500. } else {
  501. finishSelection();
  502. rectExists = false;
  503. rectDragging = false;
  504. rectPosX = cellx;
  505. rectPosY = celly;
  506. rectSizeX = -1;
  507. rectSizeY = -1;
  508. }
  509. } else {
  510. if (cellx > -1 && cellx < worldX && celly > -1 && celly < worldY){ //If the mouse is over the play area
  511. putCell(cellx,celly,drawType);
  512. }
  513. }
  514. }
  515.  
  516. function mouseMove(event){ //When the mouse moves (not just over the canvas, which is how you can draw behind the ui)
  517. cellx = Math.floor((event.clientX - crect.left)/zoom); //Mathematics to get the cell you clicked on.
  518. celly = Math.floor((event.clientY - crect.top)/zoom);
  519. if (mouseIsDown && (cellx > -1 && cellx < worldX && celly > -1 && celly < worldY)){ //If the mouse is over the play area and the mouse is down
  520. if(drawType > -1){ //If it's not the rectangle select tool, which is -1
  521. putCell(cellx,celly,drawType);
  522. } else if(!rectDragging) { //Selection gets resized as the user drags the mouse
  523. unDrawSelectionBox();
  524. rectSizeX = cellx-rectPosX;
  525. rectSizeY = celly-rectPosY;
  526. drawSelectionBox();
  527. displaySelectionDim();
  528. } else { //Selection gets moved as player drags the mouse
  529. if(cellx-rectDragX > -1 && celly-rectDragY > -1 && (cellx-rectDragX)+rectSizeX < worldX && (celly-rectDragY)+rectSizeY < worldY){ //If the selection would be moved to a place inside the world.
  530. unDrawSelectionBox();
  531. unDrawSelection();
  532. rectPosX = cellx-rectDragX;
  533. rectPosY = celly-rectDragY;
  534. drawSelectionBox();
  535. drawSelection();
  536. }
  537. }
  538. }
  539. }
  540.  
  541. function mouseUp(event){
  542. mouseIsDown = false;
  543. if(drawType == -1 && !rectDragging){ //selection tool, finish making the selection
  544. if(rectSizeX < 0){ //If the size is negative make it positve and move it over so our loops can handle it
  545. rectPosX += rectSizeX;
  546. rectSizeX = rectSizeX-rectSizeX-rectSizeX;
  547. }
  548. if(rectSizeY < 0){
  549. rectPosY += rectSizeY;
  550. rectSizeY = rectSizeY-rectSizeY-rectSizeY;
  551. }
  552. rectCellList = []; //We will create a list, rectCellList, of all the selected cells. This is useful
  553. for(y=0;y<=rectSizeY;y++){
  554. rectCellList[y] = [];
  555. for(x=0;x<=rectSizeX;x++){
  556. rectCellList[y][x] = cellList[y+rectPosY][x+rectPosX];
  557. cellList[y+rectPosY][x+rectPosX] = 0;
  558. }
  559. }
  560. rectExists = true;
  561. }
  562. }
  563.  
  564. //don't expect very useful comments if you try to figure out how the selection tool works. just expect "uhh"
  565. function unDrawSelection(){
  566. for(y=0;y<=rectSizeY;y++){ //uhh
  567. for(x=0;x<=rectSizeX;x++){
  568. if(rectCellList[y][x] != 0){
  569. drawCellAt(x+rectPosX, y+rectPosY);
  570. }
  571. }
  572. }
  573. }
  574.  
  575. function drawSelection(){
  576. for(y=0;y<=rectSizeY;y++){ //uhh
  577. for(x=0;x<=rectSizeX;x++){
  578. if(rectCellList[y][x] != 0){
  579. drawCell(x+rectPosX, y+rectPosY,rectCellList[y][x]);
  580. }
  581. }
  582. }
  583. }
  584.  
  585. function finishSelection(){
  586. if(rectExists){
  587. unDrawSelectionBox();
  588. for(y=0;y<=rectSizeY;y++){ //uhh
  589. for(x=0;x<=rectSizeX;x++){
  590. if(rectCellList[y][x] != 0){
  591. putCell(x+rectPosX, y+rectPosY, rectCellList[y][x]);
  592. }
  593. }
  594. }
  595. }
  596. }
  597.  
  598. function drawSelectionBox(){ //It's poorly made but it works
  599. canvas.beginPath();
  600. canvas.strokeStyle = "#008888";
  601. canvas.fillStyle = "#008888";
  602. canvas.fillRect(rectPosX,rectPosY,1,1); //I have to fill in the corners myself because drawRect is antialiased. Innefficient I know
  603. canvas.fillRect(rectPosX+rectSizeX,rectPosY,1,1);
  604. canvas.fillRect(rectPosX,rectPosY+rectSizeY,1,1);
  605. canvas.fillRect(rectPosX+rectSizeX,rectPosY+rectSizeY,1,1);
  606. canvas.rect(rectPosX+0.5,rectPosY+0.5,rectSizeX,rectSizeY);
  607. canvas.stroke();
  608. }
  609.  
  610. function unDrawSelectionBox(){ //replaces the pixels of the selection with the cells behind them. Simply put, undraws the selection box. Called when it has to be resized or moved or replaced or etc
  611. for(y=0;y<=Math.abs(rectSizeY);y++){
  612. if(rectSizeY >= 0){
  613. drawCellAt(rectPosX, y+rectPosY);
  614. drawCellAt(rectPosX+rectSizeX, y+rectPosY);
  615. } else {
  616. drawCellAt(rectPosX, rectPosY-y);
  617. drawCellAt(rectPosX+rectSizeX, rectPosY-y);
  618. }
  619. }
  620. for(x=0;x<=Math.abs(rectSizeX);x++){
  621. if(rectSizeX >= 0){
  622. drawCellAt(x+rectPosX, rectPosY);
  623. drawCellAt(rectPosX+x, rectPosY+rectSizeY);
  624. } else {
  625. drawCellAt(rectPosX-x, rectPosY);
  626. drawCellAt(rectPosX-x, rectPosY+rectSizeY);
  627. }
  628. }
  629. }
  630.  
  631. function displaySelectionDim(){
  632. document.getElementById("rectdisy").innerHTML = Math.abs(rectSizeY)+1;
  633. document.getElementById("rectdisx").innerHTML = Math.abs(rectSizeX)+1;
  634. }
  635.  
  636. function changeZoom(n){ //It scales the canvas itself.
  637. if(n>0){ //We don't want to be able to set zoom to 0, or -1, or whatever
  638. zoom = n;
  639. c.style.width = worldX * n + "px"; //Note the difference between c.width and c.style.width. This is only how big it appears.
  640. c.style.height = worldY * n + "px";
  641. document.getElementById("zoomCounter").innerHTML=zoom; //Display the level of zoom. Pretty obvious
  642. moveCanvas()
  643. }
  644. }
  645.  
  646. function changeDT(newDT){
  647. if(newDT > 0){
  648. speedDT = newDT;
  649. document.getElementById("DTcounter").innerHTML = speedDT*15+"ms ("+Math.round(1000/(speedDT*15))+"fps)";
  650. }
  651. }
  652.  
  653. function changeSpeedMult(newmult){
  654. if(newmult > 0){
  655. speedMult = newmult;
  656. document.getElementById("multCounter").innerHTML = speedMult;
  657. }
  658. }
  659.  
  660. function changeDrawType(newDrawType){ //Called by the items in the menu to the top left
  661. if(newDrawType<names.length){
  662. if(drawType == -1){
  663. finishSelection();
  664. rectExists = false;
  665. }
  666. document.getElementById("sel"+drawType).className = "selMenuItem";
  667. document.getElementById("sel"+newDrawType).className = "selMenuItemHighlighted";
  668. drawType = newDrawType;
  669. }
  670. }
  671.  
  672. function pausePlay(){ //This function pauses the sim if it's playing, plays it if it's paused
  673. if(!pauselock){
  674. running = !running;
  675. if(running){
  676. document.getElementById("pauseDisplay").innerHTML = "Pause";
  677. } else {
  678. document.getElementById("pauseDisplay").innerHTML = "Unpause";
  679. }
  680. }
  681. }
  682.  
  683. function pauseLock(){
  684. pauselock = !pauselock;
  685. if(pauselock){
  686. document.getElementById("pauseLockDisplay").innerHTML = "Unlock";
  687. } else {
  688. document.getElementById("pauseLockDisplay").innerHTML = "Lock";
  689. }
  690. }
  691.  
  692. //PLAGIARISED SAVECODE FUNCTIONS. cred to jack e (He didn't leave many comments on his code. I indented it myself)
  693. var saveCodeCharacterSet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  694. var LLRRdiff = [0,1,2,3,4,5,11,6,12,7,13,8,14,9,15,10,16]; //Used to convert between Logic Land's cell values and Reasoning Realm's
  695. var RRLLdiff = [0,1,2,3,4,5,7,9,11,13,15,6,8,10,12,14,16]; //Used to convert the other way. It's the inverse
  696.  
  697. function convertNumberIntoSaveCodeCharacter(number){
  698. return saveCodeCharacterSet.substring(number, number + 1);
  699. }
  700.  
  701. function convertSaveCodeCharacterIntoNumber(character){
  702. return saveCodeCharacterSet.indexOf(character);
  703. }
  704.  
  705. function convertSaveCodeIntoNumberList(text){
  706. var output = [];
  707. var index = 0;
  708. while (index < text.length){
  709. var tempCharacter = text.substring(index, index + 1);
  710. if (tempCharacter == "*"){
  711. tempCharacter = text.substring(index + 1, index + 2);
  712. var count = convertSaveCodeCharacterIntoNumber(tempCharacter);
  713. tempCharacter = text.substring(index + 2, index + 3);
  714. var tempNumber = convertSaveCodeCharacterIntoNumber(tempCharacter);
  715. while (count > 0){
  716. output.push(tempNumber);
  717. count -= 1;
  718. }
  719. index += 3;
  720. } else {
  721. var tempNumber = convertSaveCodeCharacterIntoNumber(tempCharacter);
  722. output.push(tempNumber);
  723. index += 1;
  724. }
  725. }
  726. //BEGIN SELF INSERT YEAH. This part converts the cell list of Logic Land, which seems to be 1D, to the two dimensional array format Reasoning Realm uses
  727. //It also converts between the cell type values.
  728. newOutput = [];
  729. for(y=0;y<worldY;y++){
  730. newOutput[y] = [];
  731. for(x=0;x<worldX;x++){
  732. newOutput[y][x] = LLRRdiff[output[y*worldX+x]];
  733. }
  734. }
  735. //END SELF INSERT NO
  736. return newOutput;
  737. }
  738.  
  739. function setSaveCode(text){
  740. if(running){ //This is a self insert to the plagiarized loading thing that makes the thing paused
  741. pausePlay();
  742. }
  743. var startIndex = 0;
  744. while (text.substring(startIndex, startIndex + 1) == " ")
  745. {
  746. startIndex += 1;
  747. }
  748. var endIndex = text.length;
  749. while (text.substring(endIndex - 1, endIndex) == " ")
  750. {
  751. endIndex -= 1;
  752. }
  753. var tempIndex = text.indexOf("/");
  754. var tempList = text.substring(0, tempIndex).split(",");
  755. worldX = parseInt(tempList[0]);
  756. worldY = parseInt(tempList[1]);
  757. c.height = worldY;
  758. c.width = worldX;
  759. c.style.height = worldY*zoom+"px";
  760. c.style.width = worldX*zoom+"px";
  761. var tempText = text.substring(tempIndex + 1, text.length);
  762. cellList = convertSaveCodeIntoNumberList(tempText);
  763. drawWorld();
  764. //Set the world dimension display
  765. document.getElementById("worldXDisplay").innerHTML = worldX;
  766. document.getElementById("worldYDisplay").innerHTML = worldY;
  767. }
  768.  
  769. function convertNumberListIntoSaveCode(numberList){
  770. var output = "";
  771. var startIndex = 0;
  772. var endIndex = 0;
  773. while (startIndex < numberList.length){
  774. endIndex = startIndex + 1;
  775. var startNumber = numberList[startIndex];
  776. var tempCharacter = convertNumberIntoSaveCodeCharacter(startNumber);
  777. var count = 1;
  778. while (endIndex < numberList.length && numberList[endIndex] == startNumber && count < saveCodeCharacterSet.length - 1){
  779. endIndex += 1;
  780. count += 1;
  781. }
  782. if (count < 4){
  783. while (count > 0){
  784. output += tempCharacter;
  785. count -= 1;
  786. }
  787. } else {
  788. var tempCharacter2 = convertNumberIntoSaveCodeCharacter(count);
  789. output += "*" + tempCharacter2 + tempCharacter;
  790. }
  791. startIndex = endIndex;
  792. }
  793. return output;
  794. }
  795.  
  796. function displaySaveCode(){
  797. var saveCode = worldX + "," + worldY + "/";
  798. //SELF INSERT AGAIN. Just a reversed version of the other one. Converts 2d array into 1d so Jack's code will work on it
  799. newInput = [];
  800. for(y=0;y<worldY;y++){
  801. for(x=0;x<worldX;x++){
  802. newInput[y*worldX+x] = RRLLdiff[cellList[y][x]]; //Convert between value types and all
  803. }
  804. }
  805. //END SELF INSERT
  806. saveCode += convertNumberListIntoSaveCode(newInput);
  807. document.getElementById("RRFbox").value = saveCode;
  808. }
  809. //END PLAGIARY
  810.  
  811. function keyPress(event){ //When a key is pressed, called by body.
  812. var key = event.which;
  813. if(key == 32){ //Space (pause)
  814. pausePlay();
  815. } else if(key == 37 || key == 65){ //Left cursor key (pan left)
  816. startPan(0);
  817. } else if(key == 38 || key == 87){ //Up cursor key (pan up)
  818. startPan(1);
  819. } else if(key == 39 || key == 68){ //Right cursor key (pan right)
  820. startPan(2);
  821. } else if(key == 40 || key == 83){ //Down cursor key (pan down)
  822. startPan(3);
  823. } else if(key >= 48 && key <= 57){ //Number keys (set drawType)
  824. changeDrawType(key-48);
  825. } else if(key == 82){ //R key (select tool)
  826. if(drawType != -1){
  827. changeDrawType(-1);
  828. }
  829. } else if(key == 79){ //O key (zoom out)
  830. if(zoom>1){
  831. changeZoom(zoom-1);
  832. }
  833. } else if(key == 73){ //I key (zoom in)
  834. changeZoom(zoom+1);
  835. } else if(key == 70){ //F key (simulate one frame)
  836. if(!pauselock){tick()};
  837. } else if(key == 67){ //C key (copy selection to clipboard)
  838. if(drawType == -1){
  839. clipboard = JSON.parse(JSON.stringify(rectCellList)); //Makes clipboard into a deep clone of rectCellList
  840. }
  841. } else if(key == 86){ //V key (paste clipboard to selection)
  842. if(drawType == -1){
  843. if(clipboard[0].length>worldX || clipboard.length>worldY){
  844. alert("You tried to paste from the clipboard, but the world is too small to fit the contents of the clipboard. It doesn't matter where you tried to paste it, you have to expand the world. :(");
  845. return 0;
  846. }
  847. finishSelection();
  848. rectCellList = JSON.parse(JSON.stringify(clipboard)); //Does the exact reverse of C
  849. rectSizeX = clipboard[0].length-1;
  850. rectSizeY = clipboard.length-1;
  851. displaySelectionDim();
  852. if(rectPosX+rectSizeX>worldX){ //Error-proofing; this means that the selection box will jump to the top left if its bounding box intersects the abyss. you could still probably resize the world to be smaller than the clipboard, but who would do that?
  853. rectPosX = 0;
  854. }
  855. if(rectPosY+rectSizeY>worldY){
  856. rectPosY = 0;
  857. }
  858. drawSelectionBox();
  859. drawSelection();
  860. }
  861. } else if (key == 69 || key == 88){ //E+X keys (Clear/cut selection)
  862. if(drawType == -1){
  863. if(key == 88){ //X (cut)
  864. clipboard = JSON.parse(JSON.stringify(rectCellList)); //Makes clipboard into a deep clone of rectCellList
  865. } //E and X both clear. that's what this part does:
  866. unDrawSelection();
  867. drawSelectionBox();
  868. for(y=0;y<=rectSizeY;y++){
  869. for(x=0;x<=rectSizeX;x++){
  870. rectCellList[y][x] = 0;
  871. }
  872. }
  873. }
  874. } else if(key == 173){ //- key (gate output)
  875. changeDrawType(10);
  876. } else if(key == 219){ //[ key (half zoom)
  877. changeZoom(Math.round(zoom/2));
  878. } else if(key == 221){ //] key (double zoom)
  879. changeZoom(zoom*2);
  880. } else if(key == 77){ //M key (mirror)
  881. if(drawType == -1){
  882. var newList = []
  883. unDrawSelection();
  884. for(y=0;y<=rectSizeY;y++){
  885. newList[rectSizeY-y] = rectCellList[y].slice();
  886. }
  887. for(y=0;y<=rectSizeY;y++){
  888. rectCellList[y] = newList[y].slice();
  889. }
  890. drawSelectionBox();
  891. drawSelection();
  892. }
  893. } else if(key == 78){ //N key (mirror)
  894. if(drawType == -1){
  895. var newList = [];
  896. unDrawSelection();
  897. for(y=0;y<=rectSizeY;y++){
  898. newList[y] = [];
  899. for(x=0;x<=rectSizeX;x++){
  900. newList[y][rectSizeX-x] = rectCellList[y][x];
  901. }
  902. }
  903. for(y=0;y<=rectSizeY;y++){
  904. rectCellList[y] = newList[y].slice();
  905. }
  906. drawSelectionBox();
  907. drawSelection();
  908. }
  909. } else if(key == 84){ //T key (rotate)
  910. if(drawType == -1){
  911. var newList = [];
  912. unDrawSelection();
  913. unDrawSelectionBox();
  914. for(y=0;y<=rectSizeY;y++){
  915. newList[y] = [];
  916. for(x=0;x<=rectSizeX;x++){
  917. newList[y][rectSizeX-x] = rectCellList[y][x];
  918. }
  919. }
  920. for(y=0;y<=rectSizeY;y++){
  921. rectCellList[y] = newList[y].slice();
  922. }
  923.  
  924. var newList = [];
  925. for(y=0;y<=rectSizeX;y++){
  926. newList[y] = [];
  927. for(x=0;x<=rectSizeY;x++){
  928. newList[y][x] = rectCellList[x][y];
  929. }
  930. }
  931. for(y=0;y<=rectSizeY;y++){
  932. rectCellList[y] = newList[y].slice();
  933. }
  934. rectSizeY = rectCellList.length-1;
  935. rectSizeX = rectCellList[0].length-1;
  936. drawSelectionBox();
  937. drawSelection();
  938. }
  939. } else if(key == 81){ //Q key (empty space)
  940. changeDrawType(0);
  941. } else if(key == 72){ //H key (center camera)
  942. centerCamera();
  943. }
  944. }
  945.  
  946. function keyUp(event){
  947. var key = event.which;
  948. if(key == 37 || key == 65){ //Left cursor key (pan left)
  949. endPan(0);
  950. } else if(key == 38 || key == 87){ //Up cursor key (pan up)
  951. endPan(1);
  952. } else if(key == 39 || key == 68){ //Right cursor key (pan right)
  953. endPan(2);
  954. } else if(key == 40 || key == 83){ //Down cursor key (pan down)
  955. endPan(3);
  956. }
  957. }
  958.  
  959. function startPan(dir){
  960. panning[dir] = true;
  961. }
  962. function endPan(dir){
  963. panning[dir] = false;
  964. }
  965.  
  966. function continuousPan(){ //This is called every 50 milliseconds by the script at the end of this file.
  967. if(panning[0] || panning[1] || panning[2] || panning[3]){
  968. var panAmt = 128/zoom;
  969. if(panning[0]){
  970. cameraPanX += panAmt;
  971. }
  972. if(panning[1]){
  973. cameraPanY += panAmt;
  974. }
  975. if(panning[2]){
  976. cameraPanX -= panAmt;
  977. }
  978. if(panning[3]){
  979. cameraPanY -= panAmt;
  980. }
  981. moveCanvas();
  982. }
  983. }
  984.  
  985. function pan(dir){ //This one is used by the arrow buttons in the menu.
  986. var panAmt = 128/zoom;
  987. if(dir == 0){
  988. cameraPanX += panAmt;
  989. } else if(dir == 1){
  990. cameraPanY += panAmt;
  991. } else if(dir == 2){
  992. cameraPanX -= panAmt;
  993. } else if(dir == 3){
  994. cameraPanY -= panAmt;
  995. }
  996. moveCanvas();
  997. }
  998.  
  999. function resize(){ //Expand/contract (depending on eorc) in direction "dir" by amount "amt"
  1000. var amt = Number(document.getElementById('expandAmount').value); //The number in the text box for the amount.
  1001. var tempList = []; //This array is concatenated with cellList and/or its subarrays to expand the world
  1002. //A large collection of ifs and elseifs that change the dimensions of the world, and then some operations to make sure it's drawn and rendered properly
  1003. //Due to the nature of the 2D array, it turns out the elseif chain isn't that repetitive
  1004. if(eorc){
  1005. //Expand left:
  1006. if(dir == 0){
  1007. for(i=0;i<amt;i++){
  1008. tempList[i] = 0;
  1009. }
  1010. for(y=0;y<worldY;y++){ //Templist, which is a row of amt 0s, gets concatenated with each row. horizontal expansion.
  1011. cellList[y] = tempList.concat(cellList[y]);
  1012. }
  1013. worldX += amt;
  1014. //Expand up:
  1015. } else if(dir == 1){
  1016. for(y=0;y<amt;y++){ //Templist will become a bunch of rows
  1017. tempList[y] = [];
  1018. for(x=0;x<worldX;x++){
  1019. tempList[y][x] = 0;
  1020. }
  1021. }
  1022. worldY += amt;
  1023. cellList = tempList.concat(cellList); //templist gets concatenated to cellList
  1024. //Expand right:
  1025. } else if(dir == 2){
  1026. for(i=0;i<amt;i++){
  1027. tempList[i] = 0;
  1028. }
  1029. for(y=0;y<worldY;y++){
  1030. cellList[y] = cellList[y].concat(tempList);
  1031. }
  1032. worldX += amt;
  1033. //Expand down:
  1034. } else if(dir == 3){
  1035. for(y=0;y<amt;y++){ //this is line 420 right now lol
  1036. cellList[worldY+y] = [];
  1037. for(x=0;x<worldX;x++){
  1038. cellList[worldY+y][x] = 0;
  1039. }
  1040. }
  1041. worldY += amt;
  1042. }
  1043. } else {
  1044. //Contract from left:
  1045. if(dir == 0){
  1046. for(y=0;y<worldY;y++){
  1047. cellList[y] = cellList[y].slice(amt);
  1048. }
  1049. worldX -= amt;
  1050. //contract from top:
  1051. } else if(dir == 1){
  1052. cellList = cellList.slice(amt);
  1053. worldY -= amt;
  1054. //Contract from right:
  1055. } else if(dir == 2){
  1056. for(y=0;y<worldY;y++){
  1057. cellList[y] = cellList[y].slice(0,worldX-amt);
  1058. }
  1059. worldX -= amt;
  1060. //Contract from bottom:
  1061. } else if(dir == 3){
  1062. cellList = cellList.slice(0, worldY-amt);
  1063. worldY -= amt;
  1064. }
  1065. }
  1066. c.height = worldY; //Estabish logical dimensions of the canvas after the resize.
  1067. c.width = worldX;
  1068. changeZoom(zoom); //The changezoom function does some things we're too lazy to put here
  1069. drawWorld(); //Then we probably have to redraw, to be sure
  1070. document.getElementById("worldXDisplay").innerHTML = worldX;
  1071. document.getElementById("worldYDisplay").innerHTML = worldY;
  1072. rectPosX = 0;
  1073. rectPosY = 0;
  1074. rectSizeX = 0;
  1075. rectSizeY = 0;
  1076. rectCellList = [[0]];
  1077. if(algorithm == 0){
  1078. fillSparse();
  1079. }
  1080. }
  1081.  
  1082. function eorcf(){ //This function gets used by the button that expands or contracts the world. the f is for function
  1083. eorc = !eorc;
  1084. if(eorc){
  1085. document.getElementById("eorcDisplay").innerHTML = "Expand";
  1086. } else {
  1087. document.getElementById("eorcDisplay").innerHTML = "Contract";
  1088. }
  1089. }
  1090.  
  1091. var Dirnames = ["Left","Top","Right","Bottom"]; //Used to set the text of the direction button on the resize menu
  1092.  
  1093. function dirf(){ //The direction of expanding/contracting. the f is for function
  1094. dir = (dir+1) % 4; //Cycles dir between 0,1,2,3
  1095. document.getElementById("dirDisplay").innerHTML = Dirnames[dir]; //Use of Dirnames.
  1096. }
  1097.  
  1098. function moveCanvas(){
  1099. c.style.left = Math.round(((worldX+cameraPanX)/2 *zoom)+ appWidth/2 - worldX*zoom) + "px";
  1100. c.style.top = Math.round(((worldY+cameraPanY)/2 *zoom)+ appHeight/2 - worldY*zoom) + "px";
  1101. crect = c.getBoundingClientRect(); //We know that this will change crect so we can reestablish it now
  1102. }
  1103.  
  1104. function clearWorld(){
  1105. var row = [];
  1106. for(x=0;x<worldX;x++){
  1107. row[x] = 0;
  1108. }
  1109. cellList = [];
  1110. for(y= -1;y<=worldY;y++){
  1111. cellList[y] = row.slice();
  1112. }
  1113. drawEmpty();
  1114. }
  1115.  
  1116. function drawEmpty(){ //Draws the colour of state 0 everywhere. Useful in some places.
  1117. canvas.fillStyle = "rgb("+colours[0]+")";
  1118. canvas.fillRect(0,0,worldX,worldY);
  1119. }
  1120.  
  1121. var rleValues = ".ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  1122. function getRLE(subject,height,width){ //Not a very elegant function
  1123. var output = "";
  1124. var runLength = 0;
  1125. var runType = 0;
  1126. var lineRunLength = 1;
  1127. var lineRunning = true;
  1128. var line = "";
  1129. for(y=0;y<height;y++){
  1130. runLength = 0;
  1131. lineRunning = true;
  1132. line = "";
  1133. for(x=0;x<width;x++){
  1134. if(subject[y][x] != 0){
  1135. lineRunning = false;
  1136. }
  1137. if(runType != 0 || x+1 != width){
  1138. if(runLength == 0){
  1139. runType = subject[y][x];
  1140. runLength++;
  1141. } else if(subject[y][x] == runType){
  1142. runLength++;
  1143. } else {
  1144. if(runLength>1){
  1145. line = line+runLength+rleValues.charAt(runType);
  1146. } else {
  1147. line = line+rleValues.charAt(runType);
  1148. }
  1149. runType = subject[y][x];
  1150. runLength = 1;
  1151. }
  1152. }
  1153. }
  1154. if(subject[y][width-1] > 0 && subject[y][width] != runType){
  1155. if(runLength>1){
  1156. line = line+runLength+rleValues.charAt(runType);
  1157. } else {
  1158. line = line+rleValues.charAt(runType);
  1159. }
  1160. }
  1161. if(subject[y][width-1] > 0){
  1162. if(runLength>1){
  1163. line = line+runLength+rleValues.charAt(subject[y][width-1]);
  1164. } else {
  1165. line = line+rleValues.charAt(subject[y][width-1]);
  1166. }
  1167. }
  1168. if(lineRunning){
  1169. if(y>0){
  1170. lineRunLength++;
  1171. }
  1172. } else if(lineRunLength != 0){
  1173. if(lineRunLength > 1){
  1174. output = output+lineRunLength+"$"+line;
  1175. } else {
  1176. if(y>0){
  1177. output = output+"$"+line;
  1178. } else {
  1179. output = output+line;
  1180. }
  1181. }
  1182. lineRunLength = 1;
  1183. }
  1184. }
  1185. output="x = "+width+", y = "+height+", rule = "+rule+"\n"+output;
  1186. output=output+"!";
  1187. document.getElementById('RLEbox').value = output;
  1188. }
  1189.  
  1190. function setRLE(text){
  1191. var input = text.split("\n").filter(function(line){return line != "" && line.substring(0,1) != "#"});
  1192. input[0] = input[0].replace(/ /g, "").split(",");
  1193. worldX = Number(input[0][0].slice(2));
  1194. worldY = Number(input[0][1].slice(2));
  1195. if(input[0].length > 2){
  1196. setRule(input[0][2].slice(5));
  1197. } else {
  1198. setRule("B3/S23")
  1199. }
  1200. input[0] = "";
  1201. input = input.join("");
  1202. c.height = worldY;
  1203. c.width = worldX;
  1204. c.style.height = worldY*zoom+"px";
  1205. c.style.width = worldX*zoom+"px";
  1206. clearWorld();
  1207. document.getElementById("worldXDisplay").innerHTML = worldX;
  1208. document.getElementById("worldYDisplay").innerHTML = worldY;
  1209. var numberHoldString = "";
  1210. var numberHoldInt = 1;
  1211. var headX = 0;
  1212. var headY = 0;
  1213. var unterminated = true;
  1214. for(index=0;index<input.length && unterminated;index++){
  1215. var charat = input.charAt(index);
  1216. if(charat == "$"){
  1217. headX = 0;
  1218. headY += numberHoldInt;
  1219. } else if(charat == "." || charat == "b"){
  1220. headX += numberHoldInt;
  1221. } else if(charat == "o" || charat == "A"){
  1222. for(i=0;i<numberHoldInt && headX < worldX;i++){
  1223. cellList[headY][headX] = 1;
  1224. drawCell(headX,headY,1);
  1225. headX++;
  1226. }
  1227. } else {
  1228. var charatloc = rleValues.indexOf(charat)
  1229. if(charatloc > 1){
  1230. for(i=0;i<numberHoldInt;i++){
  1231. cellList[headY][headX] = charatloc;
  1232. drawCell(headX,headY,charatloc);
  1233. headX++;
  1234. }
  1235. } else if(charat == "!"){
  1236. unterminated = true;
  1237. }
  1238. }
  1239.  
  1240. if(input.charCodeAt(index) >= 48 && input.charCodeAt(index) <= 57){
  1241. numberHoldString=numberHoldString+charat;
  1242. numberHoldInt = Number(numberHoldString);
  1243. } else {
  1244. numberHoldInt = 1;
  1245. numberHoldString = "";
  1246. }
  1247. }
  1248. moveCanvas();
  1249. fillSparse();
  1250. generation = 0;
  1251. document.getElementById("genNum").innerHTML = 0;
  1252. }
  1253.  
  1254. function setRule(newRulestring){
  1255. var rulestring = newRulestring.toLowerCase();
  1256. if(rulestring == "logicland"){ //Logic Land
  1257. colours = [[150,230,230],[225,128,50],[255,255,0],[110,64,25],[128,128,128],[150,0,150],[255,255,255],[0,0,255],[255,0,0],[0,128,0],[0,0,0],[150,0,150],[255,255,255],[0,0,255],[255,0,0],[0,128,0],[0,0,0]];
  1258. names = ["Empty Space","Inactive Wire","Active Wire","Inhibited Wire","Cross Over","NOR Gate","OR Gate","XOR Gate","AND Gate","T Flip Flop","Gate Output"];
  1259. createSelMenu();
  1260. rule = newRulestring;
  1261. transFunc = transLL;
  1262. padSparse = padSparseJvN;
  1263. } else { //Try to interpret the rulestring as lifelike or generations.
  1264. var splitrule = rulestring.split("/");
  1265. if(splitrule.length == 2) { //Lifelike rules
  1266. transFunc = transLife;
  1267. var bloc = rulestring.indexOf("b");
  1268. var sloc = rulestring.indexOf("s");
  1269. if(bloc>=sloc){ //Figuring out the order of the survival and birth conditions in the rulestring.
  1270. splitrule[2] = splitrule[0];
  1271. splitrule[0] = splitrule[1];
  1272. splitrule[1] = splitrule[2];
  1273. }
  1274. rule = newRulestring;
  1275. colours = [[255,255,255],[0,0,0]];
  1276. names = ["Dead Cell","Live Cell"];
  1277. createSelMenu();
  1278. for(t=0;t<=1;t++){
  1279. for(n=0;n<=8;n++){
  1280. if(splitrule[t].includes(n)){
  1281. transitions[t][n] = 1;
  1282. } else {
  1283. transitions[t][n] = 0;
  1284. }
  1285. }
  1286. }
  1287. transFunc = transLife;
  1288. padSparse = padSparseMoore;
  1289. } else if(splitrule.length == 3){ //Generations rules
  1290. var states = Number(splitrule[2]);
  1291. if(states != states || states < 3){ //NaN is not equal to itself. If that's true it means it's NaN
  1292. alert("FUCK! THE RULE IS INVALID BECAUSE THERE IS NO _PROPER_ THIRD PARAMETER FOR THE GENERATIONS RULE BRICKFACE DUMBCUNT ITS THE AMOUNT OF STATES. idiot");
  1293. return 0;
  1294. }
  1295. //Now we know this is a rule we can interpret properly
  1296. rule = newRulestring;
  1297. splitrule[-1] = splitrule[0]; //We have to swap b and s because I'm lazy
  1298. splitrule[0] = splitrule[1];
  1299. splitrule[1] = splitrule[-1];
  1300. for(t=0;t<=1;t++){
  1301. for(n=0;n<=8;n++){
  1302. if(splitrule[t].includes(n)){
  1303. transitions[t][n] = 1;
  1304. } else {
  1305. transitions[t][n] = 0+t+t;
  1306. }
  1307. }
  1308. }
  1309. colours = [[10,10,10],[0,0,255]];
  1310. names = ["Dead Cell","Live Cell"];
  1311. for(i=2;i<states;i++){
  1312. var hue = Math.round(255*(i/states));
  1313. colours[i] = [Math.floor(hue/3),hue,0];
  1314. names[i] = "Refractory";
  1315. }
  1316. createSelMenu();
  1317. transFunc = transGenerations;
  1318. padSparse = padSparseMoore;
  1319. }
  1320. }
  1321. drawType = 0;
  1322. changeDrawType(drawType);
  1323. }
  1324.  
  1325. function createSelMenu(){
  1326. selMenu.innerHTML="";
  1327. for(i=0;i<names.length;i++){ //This loop generates the menu.
  1328. selMenu.innerHTML = selMenu.innerHTML +
  1329. '<div onmousedown="changeDrawType('+i+')" id="sel'+i+'" class="selMenuItem"><span style="background-color:rgb('+colours[i]+');padding:0px 4px 0px 4px;"> </span>'+i+' '+names[i]+'</div>';
  1330. }
  1331. }
  1332.  
  1333. function centerCamera(){
  1334. cameraPanX=0;
  1335. cameraPanY=0;
  1336. moveCanvas();
  1337. }
  1338.  
  1339. function changeAlgorithm(){
  1340. if(algorithm == 0){
  1341. algorithm = 1;
  1342. document.getElementById("changealgobutton").innerHTML = "Brute Force";
  1343. } else {
  1344. algorithm = 0;
  1345. fillSparse();
  1346. document.getElementById("changealgobutton").innerHTML = "Ignore Non Changing Cells";
  1347. }
  1348. }
  1349. </script>
  1350. </head>
  1351. <body onkeydown="keyPress(event)" onkeyup="keyUp(event)" onmouseup="mouseUp(event)">
  1352. <div style="position:relative;width:100%;height:100%;cursor:default;overflow:hidden;background-color:#404040;" id="appContainer" onmousemove="mouseMove(event)">
  1353. <canvas height="64" width="64" id="display" onmousedown="mouseDown(event)" style="width:512px;height:512px;position:absolute;font-size:32px;">This text displays if you have javascript disabled, or I guess if your browser doesn't support canvases. If it is the latter please reconsider your life choices/kill yourself. Otherwise enable js dude</canvas>
  1354. <div style="position:absolute;top:0px;left:0px;background-color:rgba(0,0,0,0.75);border-bottom-right-radius:4px;" id="elementSelector">
  1355. <div onmousedown="changeDrawType(-1)" id="sel-1" class="selMenuItem"><span style="background-color:#008888;padding:0px 4px 0px 4px;"> </span>R Select Tool</div>
  1356. <span id="elements"></span>
  1357. </div>
  1358. <div style="position:absolute;top:0;right:0;padding:0px 6px 2px 0px;text-shadow:0px 0px 2px black;text-align:right;" onmousedown="mouseDown(event)">
  1359. V0.2.0
  1360. <!-- THE VERSION NUMBER IS HERE. Making it so it's easy to see in the source code. -->
  1361. by blah,
  1362. <a style="text-decoration:none;" href="http://www.ostracodfiles.com/logic/logicland.html">Inspired by Jack Eisenmann</a><br />
  1363. World dimensions:
  1364. <span class="number" id="worldXDisplay">64</span>x<span class="number" id="worldYDisplay">64</span><br />
  1365. Selection dimensions:
  1366. <span class="number" id="rectdisx">420</span>x<span class="number" id="rectdisy">69</span><br />
  1367. Generation <span class="number" id="genNum">413</span>, <span class="number" id="gpsdisplay">612</span> generations/second
  1368. </div>
  1369. <div style="position:absolute;bottom:-1px;background-color:rgba(0,0,0,0.75);width:100%;line-height:20px;padding:2px 4px 2px 4px;">
  1370. <span class="button" onclick="help.style.zIndex='0';help.style.opacity='1'">‽</span>
  1371. | Zoom:
  1372. <span class="button" onclick="changeZoom(zoom*2)">++</span>
  1373. <span class="button" onclick="changeZoom(zoom+1)">+</span>
  1374. <span id="zoomCounter" class="number">8</span>
  1375. <span class="button" onclick="changeZoom(zoom-1)">-</span>
  1376. <span class="button" onclick="changeZoom(Math.round(zoom/2))">--</span>
  1377. | Δt:
  1378. <span class="button" onclick="changeDT(speedDT*2)">++</span>
  1379. <span class="button" onclick="changeDT(speedDT+1)">+</span>
  1380. <span id="DTcounter" class="number">15ms (67fps)</span>
  1381. <span class="button" onclick="changeDT(speedDT-1)">-</span>
  1382. <span class="button" onclick="changeDT(Math.round(speedDT/2))">--</span>
  1383. | generations/frame:
  1384. <span class="button" onclick="changeSpeedMult(speedMult*2)">++</span>
  1385. <span class="button" onclick="changeSpeedMult(speedMult+1)">+</span>
  1386. <span id="multCounter" class="number">1</span>
  1387. <span class="button" onclick="changeSpeedMult(speedMult-1)">-</span>
  1388. <span class="button" onclick="changeSpeedMult(Math.round(speedMult/2))">--</span>
  1389. | Pan camera:
  1390. <span class="button" onclick="pan(0)">←</span>
  1391. <span class="button" onclick="pan(1)">↑</span>
  1392. <span class="button" onclick="pan(2)">→</span>
  1393. <span class="button" onclick="pan(3)">↓</span>
  1394. | <span class="button" onclick="pausePlay();" id="pauseDisplay">Pause</span>
  1395. | Logic Land save codes:
  1396. <span class="button" onclick="displaySaveCode()">get</span>
  1397. <span class="button" onclick="setSaveCode(document.getElementById('RRFbox').value)">set</span>
  1398. <input type="text" id="RRFbox" size="16" onfocus="this.select()" />
  1399. | RLE save codes:
  1400. <span class="button" onclick="getRLE(cellList,worldY,worldX)">get</span>
  1401. <span class="button" onclick="setRLE(document.getElementById('RLEbox').value)">set</span>
  1402. <textarea id="RLEbox" style="height:16px" onfocus="this.select()"></textarea>
  1403. | <span class="button" onclick="if(!pauselock){tick()}">Simulate one frame</span> <!-- This has no-break spaces in the text so that part of the button doesn't be on a different line to the rest. That happened. Remember to use nbsps! -->
  1404. | <span class="button" onclick="eorcf()" id="eorcDisplay">Expand</span>
  1405. the world by
  1406. <input type="text" id="expandAmount" size="4" value="16" onfocus="this.select()" />
  1407. pixels on the
  1408. <span class="button" onclick="dirf()" id="dirDisplay">Left</span>
  1409. <span class="button" onclick="resize()">Go</span>
  1410. | <span class="button" onclick="centerCamera()">Center Camera</span>
  1411. | <span class="button" onclick="clearWorld();">Clear World</span>
  1412. | Change Rule:
  1413. <span class="button" onclick="setRule(document.getElementById('ruleBox').value);drawWorld()">set</span>
  1414. <input type="text" id="ruleBox" size="10" value="B3/S23" onfocus="this.select()" />
  1415. | Algorithm:
  1416. <span class="button" id="changealgobutton" onclick="changeAlgorithm()">Brute Force</span>
  1417. </div>
  1418. <div id="HELP" style="
  1419. width:100%;
  1420. height:100%;
  1421. z-index:-1;
  1422. opacity:0;
  1423. position:relative;
  1424. background-color:rgba(0,0,0,0.75);
  1425. overflow:auto;
  1426. margin:auto;
  1427. -webkit-user-select: text;
  1428. -moz-user-select: text;
  1429. -ms-user-select: text;">
  1430. <span class="button" onclick="help.style.zIndex='-1';help.style.opacity='0'">Close</span>
  1431. <p>Hello. I am blah. This is the help menu, though it's not actually a menu.</p>
  1432. <!-- I've put comments in here marking sections -->
  1433. <h1>Reasoning Realm</h1>
  1434. <p>I declare this to be free software. I'm not sure how that works legally, but legalities aren't going to come into play here. Feel free to reverse engineer it, distribute it, modify it, distribute modifed versions of it, etc. I just request you give me credit.</p>
  1435. <p>This is an implementation of cellular automata in javascript. It was originally simply an implementation of Jack Eisenmann's "<a href="http://www.ostracodfiles.com/logic/logicland.html">Logic Land</a>" cellular automaton, though I realised it would have more potential if it could simulate other rules. There is currently only support for Logic Land, lifelike CA, and Generations rules, though more will be added. It can import and export patterns in extended RLE format, in addition to the undocumented format that Logic Land used (though this is neglected, do not use it) with functions copy/pasted straight from Jack Eisenmann's code, with modifications to convert it into Reasoning Realm's internal format (a 2d array, with different values for cell types). "Reasoning Realm" is a play on the name "Logic Land", obviously; Intelligence Island could be another, so could Deduction Dimension or Smartness Sphere (those last two are courtesy of Dan). I've been working on this since 2016-03-03. The text in the menus is unselectable (in browsers that support my methods) (but this text can be selected) because the buttons are spans, and if you could select the text that would happen while you were clicking the buttons. Sorry if not being able to select the text frustrates you. The clipboard is initalised to something, so if you use the selection tool to paste, without first copying, you'll see its default content. The source code of this program is over 1000 lines.</p>
  1436. <p>Credit goes to <span class="blah">BLAH (ME)</span> for being the most graceful, intelligent, all-seeing supreme being to have ever existed within or surrounding the omniverse and all other possible worlds, Jack Eisenmann for inspiration, and dan.</p>
  1437. <!-- section -->
  1438. <h2>Controls</h2>
  1439. <p>
  1440. left click and drag over the canvas with the mouse to draw the selected element<br />
  1441. wasd/arrow keys: move camera<br />
  1442. F: simulate one frame<br />
  1443. I: zoom in linearly<br />
  1444. O: zoom out linearly<br />
  1445. [: zoom out exponentially<br />
  1446. ]: zoom in exponentially<br />
  1447. space: play/pause<br />
  1448. E: erase selection<br />
  1449. X: cut selection<br />
  1450. C: copy selection<br />
  1451. V: paste selection<br />
  1452. M: mirror selection vertically<br />
  1453. N: mirror selection horizontally<br />
  1454. T: rotate selection<br />
  1455. H: center camera<br />
  1456. 0,1,2,3,4,5,6,7,8,9: select corresponding element<br />
  1457. Q: same as 0<br />
  1458. R: selection tool<br />
  1459. -: Gate Output (the hyphen key, to the right of 0)<br />
  1460. alt+f4: close help menu
  1461. </p>
  1462. <p>Pause lock. If you enable this, you will not be able to pause or unpause. useful iff you=dan <span class="button" onclick="pauseLock()" id="pauseLockDisplay">Lock</span></p>
  1463. <!-- section -->
  1464. <h2>Changelog</h2>
  1465. <h3>0.2.0</h3>
  1466. <p class="date">2016-07-03</p>
  1467. <ul class="changelist">
  1468. <li>New optimised algorithm. The code for simulating a frame has been almost entirely remade. You can choose to use the old algorithm, as it is still faster for some things.</li>
  1469. <li>Added selection size indicator to top right</li>
  1470. <li>Added hotkey H for center camera</li>
  1471. <li>Pause lock now prevents simulating single steps (hotkey F and corresponding menu item)</li>
  1472. <li>Changed background colour to #404040</li>
  1473. <li>The app now autofits the browser window, and the 'resize app' option has been removed (to make the menu less cluttered with useless options; it still worked)</li>
  1474. <li>Fixed bug where rectangle select tool would cause program halting errors if you resized to remove its origin, or pasted into a domain smaller than the clipboard.</li>
  1475. <li>Added hotkey T to rotate selection, though glitchily</li>
  1476. <li>Added generation counter and generations/second in the top right</li>
  1477. <li>Added ++ and -- buttons for changing speed</li>
  1478. <li>Added splashscreen, an RLE that gets loaded when RR starts</li>
  1479. </ul>
  1480. <!-- section -->
  1481. <h2>Todo List</h2>
  1482. <p>This is a list of easy and difficult goals. Some I will probably never bother to do. They are in no order whatsoever. This list is maintained poorly if at all.</p>
  1483. <ul>
  1484. <li>Fix the rotation.</li>
  1485. <li>Add options for colour schemes.</li>
  1486. <li>Add camera drag tool for panning the camera with the mouse.</li>
  1487. <li>Make the 'close' button in the help menu follow you as you scroll down.</li>
  1488. <li>Capture keyboard inputs for textboxes (and the help menu); right now the keyboard shortcuts are triggered when you type in a text box.</li>
  1489. <li>Add support for unbounded grids</li>
  1490. <li>Add support for other geometries, like cylinders, toruses, klein bottles, etc</li>
  1491. <li>Combine both savecode boxes into a single box which can tell what format is being used</li>
  1492. <li>Allow multiple worlds loaded at once</li>
  1493. <li>Add undo functionality</li>
  1494. <li>Bug: Changing the rule to one with n states causes errors which halt the program if there is a cell with state x>n</li>
  1495. <li>Rewrite getRLE() as it is incredibly poorly put together and glitchy.</li>
  1496. </ul>
  1497. </div>
  1498. </div>
  1499. <script>
  1500. //Script at the end of <body> to initialize the app.
  1501. var c = document.getElementById("display");
  1502. var canvas = c.getContext("2d");
  1503. var crect = c.getBoundingClientRect(); //This has to do with getting the location of the mouse over the canvas. See this stackoverflow page: http://stackoverflow.com/questions/17130395/canvas-html5-real-mouse-position
  1504. var id = canvas.createImageData(1,1); //It's worth reading this stackoverflow page for info on this variable: http://stackoverflow.com/questions/4899799/whats-the-best-way-to-set-a-single-pixel-in-an-html5-canvas
  1505. var d = id.data;
  1506. d[3] = 255; //d[3] is opacity, which should be full.
  1507. var help = document.getElementById("HELP");
  1508. var selMenu = document.getElementById("elements");
  1509. setRule("logicland");
  1510. drawWorld();
  1511. changeDrawType(1); //We have to call this so the menu doesn't have no items selected. Having no items selected is not something the menu should ever be able to do
  1512. setInterval("if(running){tickCount++; if(tickCount%speedDT == 0){tick()}}", 15); //The if statement is here, not in the function, so we can manually simulate frames. also the number is the dt in ms
  1513. crect = c.getBoundingClientRect();
  1514. appWidth = document.getElementById('appContainer').getBoundingClientRect().width;
  1515. appHeight = document.getElementById('appContainer').getBoundingClientRect().height;
  1516. setInterval("crect = c.getBoundingClientRect(); appWidth = document.getElementById('appContainer').getBoundingClientRect().width; appHeight = document.getElementById('appContainer').getBoundingClientRect().height", 5000); //It re-establishes that variable every 5 seconds because I'm too lazy to find out how to trigger an event when body is resized
  1517. setInterval("continuousPan();", 50); //This function's name is self-explanatory; it checks to see if the wasd/><^V keys are being pressed and if so moves the camera accordingly when it is called.
  1518. setInterval("document.getElementById('gpsdisplay').innerHTML = generation-gpscount; gpscount = generation;",1000);
  1519. centerCamera();
  1520. setRLE("#C This is the splash screen for Reasoning Realm. This is a comment! Yeah!!!\nx = 64, y = 64, rule = logicland\n4$7.4A2.4A2.3A3.3A2.3A2.4A2.2A.4A3.4A.BA$7.2A.2A.4A.5A.4A.5A.5A.2A.5A.5A.CA$7.2A.2A.2A3.2A.2A.2A3.2A.2A.2A.2A.2A.2A.2A.2A4.I$7.4A2.4A.2A.2A.3A2.2A.2A.2A.2A.2A.2A.2A.2A4.JA$7.2A.2A.4A.5A2.3A.2A.2A.2A.2A.2A.2A.2A.2A.2A2.I$7.2A.2A.2A3.2A.2A3.2A.2A.2A.2A.2A.2A.2A.2A.2A.2A.AJ$7.2A.2A.4A.2A.2A.4A.5A.2A.2A.2A.2A.2A.5A.I$7.2A.2A.4A.2A.2A.3A3.3A2.2A.2A.2A.2A.2A2.3A2.JA$7.DADADADADADADADADADADADADADADADADADADADADADADADAJ.I$17.4A2.4A2.3A2.2A4.7A8.IAJ$17.2A.2A.4A.5A.2A4.8A$17.2A.2A.2A3.2A.2A.2A4.2A.2A.2A$17.4A2.4A.2A.2A.2A4.2A.2A.2A$17.2A.2A.4A.5A.2A4.2A.2A.2A$17.2A.2A.2A3.2A.2A.2A4.2A.2A.2A$17.2A.2A.4A.2A.2A.5A.2A.2A.2A$17.2A.2A.4A.2A.2A.5A.2A.2A.2A2$23.J.J2.J4.2J5.J$23.J.J.J.J5.J3.J.J$23.J.J.J.J3.2J4.J.J$24.J3.J2.J.3J.J2.J4$20.2J2.J.J3.2J2.J2.3J.J.J$20.J.J.J.J3.J.J.J2.J.J.J.J$20.2J3.J4.2J2.J2.3J.3J$20.J.J2.J4.J.J.J2.J.J.J.J$20.2J3.J4.2J2.2J.J.J.J.J!");
  1521. </script>
  1522. </body>
  1523. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement