| <?xml version="1.0" standalone="no"?> |
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" |
| "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> |
| |
| <!-- |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| --> |
| <!-- ====================================================================== --> |
| <!-- Minesweeper in SVG --> |
| <!-- --> |
| <!-- @author thomas.deweese@kodak.com --> |
| <!-- @version $Id$ --> |
| <!-- ====================================================================== --> |
| |
| <svg width="450" height="500" viewBox="0 0 450 500" |
| xmlns="http://www.w3.org/2000/svg" |
| xmlns:xlink="http://www.w3.org/1999/xlink"> |
| |
| <script type="text/ecmascript"> |
| <![CDATA[ |
| // |
| // Global declarations |
| // |
| var mines0 = 8; |
| var mines1 = 40; |
| var mines2 = 99; |
| |
| var boardSize = 1; |
| var numAcross = 16; |
| var numDown = 16; |
| var numMines = 40; |
| |
| var correctFlags = 0; |
| var incorrectFlags = 0; |
| var minesLeft; |
| var board = document.getElementById("board") |
| var cover = document.getElementById("cover") |
| |
| var boardArray = new Array(numAcross*numDown); |
| var shownArray = new Array(numAcross*numDown); |
| var flagArray = new Array(numAcross*numDown); |
| var isGameOver = true; |
| var xlinkNS = "http://www.w3.org/1999/xlink"; |
| var svgNS = "http://www.w3.org/2000/svg"; |
| |
| function initBoard(evt) { |
| isGameOver = false; |
| minesLeft = numMines; |
| correctFlags = 0; |
| |
| updateText("mines", "Mines Left: "+minesLeft); |
| updateText("boardsz", "Board Size: "+numAcross+"x"+numDown); |
| updateText("title", ""); |
| updateText("working", "Working"); |
| |
| for(var y=0; y<numDown; y++) { |
| for(var x=0; x<numAcross; x++) { |
| boardArray[x+y*numAcross] = 0; |
| shownArray[x+y*numAcross] = false; |
| flagArray [x+y*numAcross] = false; |
| } |
| } |
| while (cover.lastChild != null) { |
| cover.removeChild(cover.lastChild); |
| } |
| while (board.lastChild != null) { |
| board.removeChild(board.lastChild); |
| } |
| |
| for (var i=0; i<numMines; i++) { |
| var index = Math.round(Math.random()*(numDown*numAcross)); |
| if ((index >= (numDown*numAcross)) || |
| (boardArray[index]!=0)) { |
| i--; |
| } else { |
| boardArray[index] = -1; |
| } |
| } |
| |
| for(var y=0; y<numDown; y++) { |
| |
| var coverRow = document.createElementNS(svgNS, "g"); |
| var boardRow = document.createElementNS(svgNS, "g"); |
| |
| var sum=0; |
| for (y1=y-1; y1<=y+1; y1++) { |
| if ((y1 >= 0) && |
| (y1 < numDown) && |
| (boardArray[y1*numAcross] == -1)) |
| sum++; |
| } |
| |
| for(var x=0; x<numAcross; x++) { |
| if (x-2 >= 0) { |
| for (y1=y-1; y1<=y+1; y1++) { |
| if ((y1 >= 0) && |
| (y1 < numDown) && |
| (boardArray[x-2+y1*numAcross] == -1)) |
| sum--; |
| } |
| } |
| if (x+1 < numAcross) { |
| for (y1=y-1; y1<=y+1; y1++) { |
| if ((y1 >= 0) && |
| (y1 < numDown) && |
| (boardArray[x+1+y1*numAcross] == -1)) |
| sum++; |
| } |
| } |
| |
| if (boardArray[x+y*numAcross] == 0) |
| boardArray[x+y*numAcross] = sum; |
| |
| var square = document.createElementNS(svgNS, "use"); |
| square.setAttributeNS(null, "x", ""+(x*10)); |
| square.setAttributeNS(null, "y", ""+(y*10)); |
| square.setAttributeNS(null, "onclick", |
| "handleClick(evt, "+x+","+y+")"); |
| |
| var cov = square.cloneNode(true); |
| cov.setAttributeNS(null, "id", "cover"+x+"-"+y); |
| cov.setAttributeNS(xlinkNS, "href", "#blank"); |
| var g = document.createElementNS(svgNS, "g"); |
| g.appendChild(cov); |
| coverRow.appendChild(g); |
| |
| square.setAttributeNS(null, "id", "square"+x+"-"+y); |
| if (boardArray[x+y*numAcross] == -1) |
| square.setAttributeNS(xlinkNS, "href", "#bomb"); |
| else |
| square.setAttributeNS(xlinkNS, "href", "#square"+sum); |
| var g = document.createElementNS(svgNS, "g"); |
| g.appendChild(square); |
| boardRow.appendChild(g); |
| } |
| cover.appendChild(coverRow); |
| board.appendChild(boardRow); |
| } |
| |
| updateText("working", ""); |
| updateText("title", "SVG Mines"); |
| } |
| |
| function handleClick(evt, x, y) { |
| if (isGameOver) return; |
| if ((evt.button == 1) || |
| (evt.shiftKey)) { |
| placeFlag(x, y); |
| } |
| else if ((evt.button == 2) || |
| (evt.ctrlKey)) { |
| showConnected(x, y); |
| } |
| else if (evt.button == 0) { |
| showSpot(x, y) |
| } |
| } |
| |
| function placeFlag(x ,y) { |
| var idx = x + y*numAcross; |
| if (shownArray[idx]) return; |
| var elt = document.getElementById("cover"+x+"-"+y); |
| var nelt = elt.cloneNode(true); |
| if (flagArray[idx]) { |
| nelt.setAttributeNS(xlinkNS, "href", "#blank"); |
| flagArray[idx] = false; |
| if (boardArray[idx] == -1) correctFlags--; |
| else incorrectFlags--; |
| minesLeft++; |
| } else { |
| nelt.setAttributeNS(xlinkNS, "href", "#flag"); |
| flagArray[idx] = true; |
| if (boardArray[idx] == -1) correctFlags++; |
| else incorrectFlags++; |
| minesLeft--; |
| } |
| |
| elt.parentNode.replaceChild(nelt, elt); |
| updateText("mines", "Mines Left: "+minesLeft); |
| |
| if ((correctFlags == numMines) && (incorrectFlags == 0)) { |
| youWin(); |
| } |
| } |
| |
| function showSpot(x, y) { |
| var idx = x + y*numAcross; |
| if (shownArray[idx]) return; |
| |
| var elt = document.getElementById("cover"+x+"-"+y); |
| elt.parentNode.parentNode.removeChild(elt.parentNode); |
| shownArray[idx] = true; |
| |
| var val = boardArray[idx]; |
| if (val == -1) { |
| gameOver(); |
| } else if (val == 0) { |
| showConnected(x, y); |
| } |
| } |
| |
| function showConnected(x, y) { |
| for (var dy=-1; dy<=1; dy++) { |
| if (y+dy < 0) continue; |
| if (y+dy >= numDown ) continue; |
| for (var dx=-1; dx<=1; dx++) { |
| if (x+dx < 0) continue; |
| if (x+dx >= numDown ) continue; |
| var idx = x+dx + (y+dy)*numAcross; |
| if (shownArray[idx]) continue; |
| if (flagArray[idx]) continue; |
| |
| var elt = document.getElementById("cover"+(x+dx)+"-"+(y+dy)); |
| elt.parentNode.parentNode.removeChild(elt.parentNode); |
| shownArray[idx] = true; |
| |
| var val = boardArray[idx]; |
| if (val == -1) { |
| gameOver(); |
| } else if (val == 0) { |
| showConnected(x+dx, y+dy); |
| } |
| } |
| } |
| } |
| |
| function gameOver() { |
| isGameOver=true; |
| updateText("title", "Game Over"); |
| showBoard(); |
| } |
| |
| function showBoard() { |
| while (cover.lastChild != null) { |
| cover.removeChild(cover.lastChild); |
| } |
| var nc = numAcross*numDown; |
| for (var i=0; i<nc; i++) |
| shownArray[i] = true; |
| } |
| |
| function youWin() { |
| isGameOver=true; |
| updateText("title", "You Win"); |
| } |
| |
| function updateText(id, lbl) { |
| var elt = document.getElementById(id); |
| var grp = elt.parentNode; |
| var newelt = elt.cloneNode(true); |
| |
| if (newelt.firstChild == null) { |
| newelt.appendChild(document.createTextNode(lbl)); |
| } else { |
| newelt.replaceChild(document.createTextNode(lbl), newelt.firstChild); |
| } |
| grp.replaceChild(newelt, elt); |
| } |
| |
| function largerBoard(evt) { |
| if (boardSize == 1) return; |
| boardSize++; |
| if (boardSize == 1) { |
| numAcross = 16; |
| numDown = 16; |
| numMines = mines1; |
| } |
| else if (boardSize == 2) { |
| numAcross = 30; |
| numDown = 16; |
| numMines = mines2; |
| } |
| updateText("boardsz", "Board Size: "+numAcross+"x"+numDown); |
| updateText("title", ""); |
| updateText("working", "Working"); |
| setTimeout("initBoard()", 50); |
| } |
| |
| function smallerBoard(evt) { |
| if (boardSize == 0) return; |
| boardSize--; |
| if (boardSize == 0) { |
| numAcross = 8; |
| numDown = 8; |
| numMines = mines0; |
| } |
| else if (boardSize == 1) { |
| numAcross = 16; |
| numDown = 16; |
| numMines = mines1; |
| } |
| updateText("boardsz", "Board Size: "+numAcross+"x"+numDown); |
| updateText("title", ""); |
| updateText("working", "Working"); |
| setTimeout("initBoard()", 50); |
| } |
| |
| function newGame(evt) { |
| updateText("title", ""); |
| updateText("working", "Working"); |
| setTimeout("initBoard()", 50); |
| } |
| |
| ]]> |
| </script> |
| |
| <defs> |
| <radialGradient id="bombGrad" gradientUnits="userSpaceOnUse" |
| cx="5" cy="6.5" fx="4" fy="5" r="2.5"> |
| <stop offset="0%" stop-color="#FFF"/> |
| <stop offset="20%" stop-color="#888"/> |
| <stop offset="100%" stop-color="#000"/> |
| </radialGradient> |
| <path id="empty" style="fill:#AAA; stroke:#DDD; stroke-width:0.5;" |
| d="M0.25,0.25 h9.5 v9.5 h-9.5 v-9.5"/> |
| |
| <g id="blank" |
| ><rect style="fill:#AAA" width="10" height="10" |
| /><path style="fill:#DDD" |
| d="M0,0 h10 l-1,1 h-8 v8 l-1,1 v-10" |
| /><path style="fill:#888" |
| d="M10,10 h-10 l1,-1 h8 v-8 l1,-1 v10" |
| /></g> |
| |
| <use id="square0" xlink:href="#empty"/> |
| <g id="square1" style="text-anchor:middle; font-size:8;" |
| ><use xlink:href="#empty" |
| /><text x="5" y="8" fill="#008" pointer-events="none">1</text></g> |
| <g id="square2" style="text-anchor:middle; font-size:8;" |
| ><use xlink:href="#empty" |
| /><text x="5" y="8" fill="#00C" pointer-events="none">2</text></g> |
| <g id="square3" style="text-anchor:middle; font-size:8;" |
| ><use xlink:href="#empty" |
| /><text x="5" y="8" fill="#40F" pointer-events="none">3</text></g> |
| <g id="square4" style="text-anchor:middle; font-size:8;" |
| ><use xlink:href="#empty" |
| /><text x="5" y="8" fill="#80C" pointer-events="none">4</text></g> |
| <g id="square5" style="text-anchor:middle; font-size:8;" |
| ><use xlink:href="#empty" |
| /><text x="5" y="8" fill="#C0C" pointer-events="none">5</text></g> |
| <g id="square6" style="text-anchor:middle; font-size:8;" |
| ><use xlink:href="#empty" |
| /><text x="5" y="8" fill="#F08" pointer-events="none">6</text></g> |
| <g id="square7" style="text-anchor:middle; font-size:8;" |
| ><use xlink:href="#empty" |
| /><text x="5" y="8" fill="#F04" pointer-events="none">7</text></g> |
| <g id="square8" style="text-anchor:middle; font-size:8;" |
| ><use xlink:href="#empty" |
| /><text x="5" y="8" fill="#F00" pointer-events="none">8</text></g> |
| |
| <g id="bomb" |
| ><use xlink:href="#empty" |
| /><rect fill="#000" x="4" y="3" width="2" height="2" |
| /><circle fill="url(#bombGrad)" cx="5" cy="6.5" r="2.5" |
| /><path fill="none" stroke="#000" stroke-width="0.3" |
| d="M5,3 c0,-1.5 1.5,-1.5 1.5,0 c0,1.5 1.5,1.5 1.5,0" |
| /></g> |
| |
| <g id="flag" |
| ><use xlink:href="#blank" |
| /><path d="M3.5,2 h.5 v6.5 h-1 l.5,-6.5" |
| /><path fill="crimson" d="M4,2 l4,1.5 l-4,1.5 z" |
| /></g> |
| </defs> |
| |
| <g id="body"> |
| <text id="title" x="25" y="60" font-size="40" |
| pointer-events="none">SVG Mines</text> |
| <text id="mines" x="250" y="30" font-size="20" |
| pointer-events="none">Mines Left: </text> |
| |
| <text id="boardsz" x="250" y="54" font-size="20" |
| pointer-events="none">Board Size: </text> |
| <g transform="translate(242, 38)" fill="black"> |
| <path onclick="largerBoard(evt)" |
| d="M2.5,0 l-2.5,7 h5 z"/> |
| <path onclick="smallerBoard(evt)" |
| d="M0,9 h5 l-2.5,7 z"/> |
| </g> |
| |
| <g text-anchor="middle" > |
| <g id="help" > |
| <desc xml:space="preserve" |
| >Left: show |
| Right or Shift: place flag |
| Middle or Control: show surround</desc> |
| <circle cx="430" cy="18" r="12" |
| fill="grey" stroke="lightgrey" stroke-width="2" /> |
| <text font-size="15" fill="blue" x="430" y="25" |
| pointer-events="none">?</text> |
| </g> |
| |
| <g onclick="newGame()"> |
| <desc xml:space="preserve">Start new game</desc> |
| <circle cx="430" cy="48" r="12" |
| fill="grey" stroke="lightgrey" stroke-width="2" /> |
| <text font-size="10" fill="blue" x="430" y="53" |
| pointer-events="none">NG</text> |
| </g> |
| </g> |
| |
| <g id="field" transform="translate(25,75) scale(2)" |
| onload="initBoard(evt)"> |
| <g id="board"> |
| </g> |
| |
| <g id="cover"> |
| </g> |
| </g> |
| <text id="working" fill="green" x="25" y="60" font-size="40" |
| pointer-events="none">Working</text> |
| </g> |
| |
| <!-- ============================================================= --> |
| <!-- Batik sample mark --> |
| <!-- ============================================================= --> |
| <use xlink:href="batikLogo.svg#Batik_Tag_Box" /> |
| </svg> |