Guest User

Untitled

a guest
Oct 27th, 2022
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.69 KB | None | 0 0
  1. const SVGLoaded = importScripts('https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.1.2/svg.min.js');
  2.  
  3. console.log(SVGLoaded);
  4.  
  5. Macro.add('SymmetryGame', {
  6. tags: [],
  7. async handler() {
  8. const wrapper = document.createElement('div');
  9. this.output.appendChild(wrapper);
  10.  
  11. await SVGLoaded;
  12. /* This function is executed when your game is finished */
  13. const gameFinished = (numUserDrawn, numLinesOnGrid) => {
  14. State.setVar('_numUserDrawn', numUserDrawn);
  15. State.setVar('_numLinesOnGrid', numLinesOnGrid);
  16. jQuery(wrapper).wiki(this.payload[0].contents);
  17. };
  18.  
  19. /* this is a prototype for a game, in which users are asked to 'draw' symmetric figures:
  20. At the start a grid with the with of n (n being an odd number) is constructed. An axis is drawn by
  21. calculating the horizontal center of the grid. Two containers are generated: The 'original container' holds the dots on top of the horizontal axis, the 'userContainer' holds the dots below. At the beginning, a series of lines is being calculated, the number of lines equals gridSize-3, e.g. in a 5-grid, two lines are drawn, in a 7-grid four lines, etc.
  22. The user can draw lines by clicking on two dots (below the axis), if the drawn line is symmetrical to the original drawing above the axis, one of the progress bars switches from white to green. Unwanted lines can be removed by clicking on them.
  23. My goal is to use this as a macro in SugarCube to call it conveniently from within a passage. It should report whether a puzzle was solved and how many lines were drawn before it was solved.
  24.  
  25. Also, in a future version, (and this might be of greater use for other twine creators), it would be great if one could pass a drawing to the macro, e.g.
  26. -x--x--x--x--x--
  27. --x-xx-xx-xx-x--
  28. ---xx-xx-xx-xx--
  29. ----x--x--x--x--
  30. ----------------
  31.  
  32. from which the original drawing is being created. This could prove useful for may puzzles I recon.
  33. */
  34.  
  35.  
  36. //set up grid, declare vars
  37.  
  38. let gridSize = parseInt(this.args[0] || 7);
  39. if (gridSize%2 ==0){
  40. gridSize--;
  41. }
  42. let originalLineCount=gridSize-2;
  43. let foundLines = 0;
  44. let foundPoints = 0;
  45. let middle = (Math.ceil(gridSize/2))-1;
  46. let gridDimension = 600;
  47. let padding = Math.floor(gridDimension/(gridSize+1));
  48. console.log("padding: " + padding);
  49. let dot = {};
  50. let userLines = {};
  51. let userLineCounter = 0;
  52. var draw = SVG().addTo(wrapper).size(gridDimension, gridDimension);
  53. let progressBars = {}
  54. let vertices = {};
  55. let activeDots = {};
  56.  
  57. //colors
  58.  
  59. let green= '#00854d';
  60. let darkPurple = '#524f6d';
  61. let yellow = '#ffb100';
  62. let activePink = '#bb44a3';
  63.  
  64.  
  65.  
  66.  
  67.  
  68. //function drawLine + check: ok
  69.  
  70. function drawLine(startPoint, endPoint, color, id) {
  71. let x1 = (startPoint[0]+1)*padding;
  72. let y1 = (startPoint[1]+1)*padding;
  73. let x2 = (endPoint[0]+1)*padding;
  74. let y2 = (endPoint[1]+1)*padding;
  75.  
  76. userLines[id] = draw.line([[x1,y1],[x2,y2]]).stroke({width:4, color:color}).attr({'id':id}).back();
  77. console.log(userLines[id]);
  78. userLines[id].node.dataset.p1 = startPoint.join(',');
  79. userLines[id].node.dataset.p2 = endPoint.join(',');
  80. if(id.slice(0, 8)=="userline"){
  81. userLines[id].on('click', () => deleteLine(id));
  82. }
  83. }
  84.  
  85.  
  86.  
  87. //draw axis
  88.  
  89. function drawAxis(gridSize) {
  90. drawLine([-1,middle],[gridSize, middle], 'darkslategrey', "symmetryAxis");
  91. }
  92. drawAxis(gridSize);
  93.  
  94.  
  95.  
  96.  
  97.  
  98. //calculate vertical symmetry
  99.  
  100. function calcSymmetry(point){
  101. let x1 = point[0];
  102. let y1 = point[1];
  103.  
  104. let symx1 = x1
  105. let symy1 = middle + (middle-y1);
  106. return([symx1, symy1]);
  107.  
  108. }
  109.  
  110.  
  111.  
  112. //start drawing when interactive dot is clicked
  113.  
  114. function startDraw(x, y) {
  115. let id = x + "-" + y;
  116. console.log(x, y);
  117. if (!dot[id].isActive) {
  118. console.log("inactive");
  119. dot[id].fill(activePink).stroke('transparent').radius(7);
  120. dot[id].isActive = true;
  121. activeDots[id] = [x,y];
  122. } else {
  123. console.log("active");
  124. dot[id].fill(yellow).stroke(green).radius(5);
  125. dot[id].isActive = false;
  126. delete activeDots[id];
  127. }
  128. console.log("ActiveDots: ", activeDots);
  129. console.log("activeDots.length: " + Object.keys(activeDots).length);
  130.  
  131. const lineDots = Object.entries(activeDots).map(([key, value]) => ({key, value}));
  132. if(lineDots.length==2){
  133. // If this line already exists, cancel
  134. if (Object.values(userLines).some((userLine) => {
  135. if (userLine.node.dataset.p1 === lineDots[0].value.join(',') && userLine.node.dataset.p2 === lineDots[1].value.join(',')) return true;
  136. if (userLine.node.dataset.p2 === lineDots[0].value.join(',') && userLine.node.dataset.p1 === lineDots[1].value.join(',')) return true;
  137. return false;
  138. })) {
  139. Object.keys(activeDots).forEach(key => delete activeDots[key]);
  140. return;
  141. }
  142.  
  143. let pointA = lineDots[0].value;
  144. let pointB = lineDots[1].value;
  145. let lineIdentifier = "userline" + userLineCounter;
  146. drawLine(pointA, pointB, '#ccc', lineIdentifier);
  147. userLineCounter++;
  148. //active Dots inaktiv stellen
  149. for (const lineDot of lineDots) {
  150. dot[lineDot.key].isActive = false;
  151. dot[lineDot.key].fill('#fff').stroke('#000').radius(5);
  152. }
  153.  
  154. //check for matches
  155. checkSymmetry(pointA, pointB, lineIdentifier);
  156.  
  157. //erase activeDots
  158. Object.keys(activeDots).forEach(key => delete activeDots[key]);
  159. }
  160. }
  161.  
  162.  
  163. //helper function for deleting lines
  164.  
  165. let retrieveLineCoordinates = function(line){
  166. let lineToFind = document.getElementById(line);
  167. let x1 = (lineToFind.getAttribute('x1')/padding-1);
  168. let y1 = (lineToFind.getAttribute('y1')/padding-1);
  169. let x2 = (lineToFind.getAttribute('x2')/padding-1);
  170. let y2 = (lineToFind.getAttribute('y2')/padding-1);
  171. console.log("x1: " + x1, "y1: " + y1, "x2: " + x2, "y2: " + y2 )
  172. return [[x1, y1], [x2, y2]];
  173. }
  174.  
  175.  
  176.  
  177. //delete line if clicked on
  178.  
  179. let deleteLine = function(id) {
  180. //look for vertices
  181. retrieveLineCoordinates(id);
  182.  
  183. //get dots x and y, reset dots
  184. let startDotId = retrieveLineCoordinates(id)[0][0] + "-" + retrieveLineCoordinates(id)[0][1];
  185. let endDotId = retrieveLineCoordinates(id)[1][0] + "-" + retrieveLineCoordinates(id)[1][1];
  186. dot[startDotId].fill(yellow).stroke(green).radius(5);
  187. dot[startDotId].fill(yellow).stroke(green);
  188. dot[endDotId].fill(yellow).stroke(green).radius(5);
  189. //remove line
  190. userLines[id].remove();
  191. }
  192.  
  193.  
  194. //define original container
  195.  
  196. let originalContainer = {};
  197. for (let i=0;i<gridSize; i++){
  198. for(let j=0; j<Math.floor(gridSize/2);j++){
  199. let id = i + "-" + j
  200. originalContainer[id]=([i,j]);
  201. console.log("originalContainer: " + Object.keys(originalContainer));
  202. console.log("originalContainer: " + Object.values(originalContainer));
  203. }
  204. }
  205.  
  206. let drawDots = function(container, interactive, fillColor, strokeColor){
  207. console.log("arrayLength: " + Object.keys(container).length);
  208. let startPoint = Object.values(container)[0];
  209. console.log("startPointY: " + startPoint[1]);
  210. for (let i=0; i<gridSize; i++){
  211. for (let j=startPoint[1]; j<(startPoint[1]+Math.floor(gridSize/2)); j++){
  212. let id = i + "-" + j;
  213. dot[id] = draw.circle(10).attr({
  214. 'fill':fillColor,
  215. 'stroke':strokeColor,
  216. }).cx(i*padding+padding).cy(j*padding+padding)
  217. dot[id].isActive = false;
  218. if(interactive){
  219. dot[id].on('click', () => startDraw(i, j)),
  220. dot[id].isActive = false;
  221. }}
  222. }
  223. }
  224.  
  225.  
  226. drawDots(originalContainer, false, 'white', '#525f6d');
  227.  
  228. let userContainer = {};
  229. for (let i=0;i<gridSize; i++){
  230. for(let j=Math.ceil(gridSize/2); j<gridSize;j++){
  231. let id = i + "-" + j
  232. userContainer[id]=([i,j]);
  233. console.log("userContainer: " + Object.keys(userContainer));
  234. console.log("userContainer: " + Object.values(userContainer));
  235. console.log("userContainer: " + userContainer);
  236. }
  237. }
  238.  
  239.  
  240. drawDots(userContainer, true, yellow, green);
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251. //generate original lines
  252.  
  253. let createOriginalLines = function(lineCount) {
  254. //chose random points from original container
  255. for(let g=0; g<lineCount; g++){
  256. let values = Object.values(originalContainer);
  257. let randomPoint = values[Math.floor(Math.random() * values.length)];
  258. console.log("randomPoint: " + randomPoint);
  259. vertices[g] = randomPoint;
  260. let index = randomPoint[0] + "-" + randomPoint[1];
  261. console.log("index: " + index);}
  262.  
  263. //rerun function if duplicates found
  264. if( hasDuplicates(Object.values(vertices)) ){
  265. console.log("duplicates found, recalculate!");
  266. console.log("vertices:" + Object.values(vertices));
  267. for (const key in vertices) {
  268. delete vertices[key];}
  269. console.log("vertices after erasing:" + Object.values(vertices));
  270.  
  271. console.log("vertices.length after erasing" + Object.values(vertices).length);
  272.  
  273. createOriginalLines(lineCount);
  274. }
  275.  
  276.  
  277. console.log("vertices new: " + Object.keys(vertices));
  278. for(let z=0; z<Object.keys(vertices).length; z++){
  279. let indix = Object.values(vertices)[z][0] + "-" + Object.values(vertices)[z][1]
  280. console.log("indix" + indix);
  281. dot[indix].fill(darkPurple);
  282. }
  283.  
  284. // draw original lines
  285. console.log("verticeskeys" + Object.keys(vertices));
  286. console.log("verticesvalues" + Object.values(vertices));
  287.  
  288. for(let n=0; n<originalLineCount; n++){
  289. if(n<(originalLineCount-1)){
  290. console.log("drawing line Nr: " + n + " from " + Object.values(vertices)[n][0] + "/" + Object.values(vertices)[n][1] + "to " + Object.values(vertices)[n+1][0] + "/" + Object.values(vertices)[n+1][1]);
  291. let id='original' + "-" + Object.values(vertices)[n][0] + "-" + Object.values(vertices)[n][1] + "-" + Object.values(vertices)[n+1][0] + "-" + Object.values(vertices)[n+1][1];
  292. console.log("line id = " + id);
  293. drawLine( Object.values(vertices)[n], Object.values(vertices)[n+1], darkPurple, id);}
  294. }
  295. }
  296. createOriginalLines(originalLineCount);
  297.  
  298. let checkSymmetry = function(pointA, pointB, lineIdentifier){
  299. console.log("pointA: " + pointA);
  300. console.log("pointB: " + pointB);
  301. console.log("vertices" + Object.values(vertices));
  302. console.log(vertices);
  303. let symA = calcSymmetry(pointA);
  304. console.log("symA: " + symA);
  305. let symB = calcSymmetry(pointB);
  306. console.log("symA: " + symB);
  307. let lineForth="original-"+symA[0]+"-"+symA[1]+"-"+symB[0]+"-"+symB[1];
  308. console.log("lineForth: " + lineForth);
  309. let lineBack="original-"+symB[0]+"-"+symB[1]+"-"+symA[0]+"-"+symA[1];
  310. console.log("lineBack: " + lineBack);
  311. if(userLines[lineForth] || userLines[lineBack]){
  312. console.log("lineForth or lineBack exists!");
  313. userLines[lineIdentifier].stroke(green);
  314. userLines[lineIdentifier].off('click');
  315. let pointAId = pointA[0]+"-"+pointA[1];
  316. let pointBId = pointB[0]+"-"+pointB[1];
  317. dot[pointAId].fill(green).stroke(green);
  318. dot[pointBId].fill(green).stroke(green);
  319. foundLines++;
  320. updateProgressBar(foundLines);
  321. console.log("Line " + foundLines + " of " + (originalLineCount-1) + " found");
  322. foundPoints=0;
  323. if (foundLines == (originalLineCount-1)){
  324. console.log("finished!");
  325. gameFinished(userLineCounter, (originalLineCount-1));
  326. }
  327. }
  328. }
  329.  
  330.  
  331. function hasDuplicates(arr) {
  332. return arr.some(x => arr.indexOf(x) !== arr.lastIndexOf(x));
  333. }
  334.  
  335.  
  336. function drawProgressBar() {
  337. let barCount = originalLineCount-1;
  338. let barHeight = gridDimension/40;
  339. let padding = gridDimension/40;
  340. let barWidth = ((gridDimension-padding*(barCount+1))/barCount);
  341. let barContainer = draw.group().attr({id:"barContainer"});
  342. let barBackground = draw.rect(gridDimension, barHeight*4).attr({fill:'#fff'}).y(gridDimension*.94);
  343. barContainer.add(barBackground);
  344. for (let s=1; s<=barCount; s++){
  345. let id=s;
  346.  
  347. progressBars[id] = draw.rect(barWidth, barHeight).attr({
  348. 'fill':'#fff',
  349. 'stroke':'#ccc',
  350. }).x((s-1)*barWidth+padding*s).y(gridDimension*.96)
  351. barContainer.add(progressBars[id]);
  352.  
  353. }
  354.  
  355. }
  356.  
  357. drawProgressBar();
  358.  
  359. function updateProgressBar(progress){
  360. progressBars[progress].fill(green);
  361. }
  362.  
  363.  
  364.  
  365.  
  366. console.log(vertices);
  367. }
  368. });
Advertisement
Add Comment
Please, Sign In to add comment