├── third_party ├── poweredByWikidata.png ├── jquery.ui.touch-punch.min.js └── README ├── index.html ├── README ├── CONTRIBUTING ├── main.css ├── about.html ├── LICENSE └── main.js /third_party/poweredByWikidata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/everythingisconnected/HEAD/third_party/poweredByWikidata.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Everything is connected 6 | 7 | 8 | 9 | 10 |

Everything is connected

11 |

12 |
13 |
14 | 18 | Show Wikipedia Article 19 |
20 | [help] 21 |

[image sources]

22 |

23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Everything is connected 2 | 3 | A knowledge puzzle game. For more user-facing information, see about.html. 4 | 5 | This is not an official Google product. 6 | 7 | The code is rather straightforward. Most of the trouble is about getting it 8 | to run decently on mobile. Last time I checked, there was still a problem on 9 | iOS (the tiles seem off). 10 | 11 | There is no backend (besides Wikidata itself). The game runs entirely in the 12 | browser. 13 | 14 | Terminology from the code: 15 | * a tile is a single piece of the puzzle, whether it is in the deck or on the 16 | board. 17 | * the board is the place where all the tiles will eventually end up. 18 | * the deck is the set of tiles that the player has available. 19 | 20 | The starting tiles are literally part of the board, that is why they cannot 21 | be moved. The code for the tiles in the deck and on the board overlap. 22 | 23 | If you create new puzzles, please put them on my Wikidata user page: 24 | https://www.wikidata.org/wiki/User:Denny/Everything_is_conntected 25 | so that others can find them. 26 | 27 | If you want to take over the maintenance of the code, I'd be very happy. Please 28 | contact me at vrandecic@google.com 29 | 30 | Third party content is provided in the third_party directory and described 31 | in third_party/README 32 | 33 | -------------------------------------------------------------------------------- /third_party/jquery.ui.touch-punch.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery UI Touch Punch 0.2.3 3 | * 4 | * Copyright 2011–2014, Dave Furfero 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * 7 | * Depends: 8 | * jquery.ui.widget.js 9 | * jquery.ui.mouse.js 10 | */ 11 | !function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery); -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at the end). 2 | 3 | ### Before you contribute 4 | Before we can use your code, you must sign the 5 | [Google Individual Contributor License Agreement] 6 | (https://cla.developers.google.com/about/google-individual) 7 | (CLA), which you can do online. The CLA is necessary mainly because you own the 8 | copyright to your changes, even after your contribution becomes part of our 9 | codebase, so we need your permission to use and distribute your code. We also 10 | need to be sure of various other things—for instance that you'll tell us if you 11 | know that your code infringes on other people's patents. You don't have to sign 12 | the CLA until after you've submitted your code for review and a member has 13 | approved it, but you must do it before we can put your code into our codebase. 14 | Before you start working on a larger contribution, you should get in touch with 15 | us first through the issue tracker with your idea so that we can help out and 16 | possibly guide you. Coordinating up front makes it much easier to avoid 17 | frustration later on. 18 | 19 | ### Code reviews 20 | All submissions, including submissions by project members, require review. We 21 | use Github pull requests for this purpose. 22 | 23 | ### The small print 24 | Contributions made by corporations are covered by a different agreement than 25 | the one above, the 26 | [Software Grant and Corporate Contributor License Agreement] 27 | (https://cla.developers.google.com/about/google-corporate). -------------------------------------------------------------------------------- /third_party/README: -------------------------------------------------------------------------------- 1 | THIRD PARTY CONTENT 2 | 3 | This directory contains third party content. 4 | This consists of the following two elements: 5 | 1) jQuery UI Touch Punch code 6 | 2) powered by Wikidata logo 7 | 8 | 9 | 1) jQuery UI Touch Punch 10 | Copyright Dave Furfero. 11 | Used under the MIT license. 12 | 13 | Source: http://touchpunch.furf.com/ 14 | 15 | The MIT License (MIT) 16 | Copyright (c) 2011-2014, Dave Furfero. 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining 19 | a copy of this software and associated documentation files (the "Software"), 20 | to deal in the Software without restriction, including without limitation 21 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 22 | and/or sell copies of the Software, and to permit persons to whom the 23 | Software is furnished to do so, subject to the following conditions: 24 | 25 | The above copyright notice and this permission notice shall be included 26 | in all copies or substantial portions of the Software. 27 | 28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 29 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 31 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 33 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 34 | THE SOFTWARE. 35 | 36 | 37 | 2) powered by Wikidata logo 38 | Created by Charlie Kritschmar, copyright by Wikimedia Deutschland e.V. 39 | Provided under Creative Commons CC-1.0 Universal Public Domain Dedication. 40 | 41 | Source: https://commons.wikimedia.org/wiki/File:Wikidata_Stamp_RecL_ight.svg 42 | 43 | The person who associated a work with this deed has dedicated the work to 44 | the public domain by waiving all of his or her rights to the work worldwide 45 | under copyright law, including all related and neighboring rights, to the 46 | extent allowed by law. You can copy, modify, distribute and perform the 47 | work, even for commercial purposes, all without asking permission. 48 | 49 | -------------------------------------------------------------------------------- /main.css: -------------------------------------------------------------------------------- 1 | /** Copyright 2016 Google Inc. 2 | /* 3 | /* Licensed under the Apache License, Version 2.0 (the "License"); 4 | /* you may not use this file except in compliance with the License. 5 | /* You may obtain a copy of the License at 6 | /* 7 | /* http://www.apache.org/licenses/LICENSE-2.0 8 | /* 9 | /* Unless required by applicable law or agreed to in writing, software 10 | /* distributed under the License is distributed on an "AS IS" BASIS, 11 | /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | /* See the License for the specific language governing permissions and 13 | /* limitations under the License. 14 | */ 15 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,600,700,800&subset=latin,cyrillic-ext,greek-ext,vietnamese,greek,latin-ext,cyrillic); 16 | 17 | body { 18 | font-family: 'Open Sans', sans-serif; 19 | background-color: #FAF9F4; 20 | color: #564A37; 21 | } 22 | a { 23 | text-decoration : none; 24 | } 25 | #board { 26 | height: 100px; 27 | width: 100px; 28 | top: 80px; 29 | left: 10px; 30 | background: #BAB9B4; 31 | position: absolute; 32 | } 33 | .tile { 34 | width: 80px; 35 | height: 80px; 36 | padding: 5px; 37 | position: absolute; 38 | } 39 | .tile span { 40 | background-color: rgba(255, 255, 255, 0.7); 41 | font-size: 80%; 42 | -ms-word-break: break-all; 43 | word-break: break-all; 44 | word-break: break-word; 45 | -webkit-hyphens: auto; 46 | -moz-hyphens: auto; 47 | hyphens: auto; 48 | } 49 | .fixed { 50 | outline: 3px solid #000; 51 | } 52 | .connection { 53 | width: 20px; 54 | height: 20px; 55 | position: absolute; 56 | text-align: center; 57 | cursor: default; 58 | } 59 | .nofit { 60 | background-color: #ff8888; 61 | } 62 | .fit { 63 | background-color: #333333; 64 | } 65 | .fit .popup { 66 | position: absolute; 67 | top: 3px; 68 | left: 3px; 69 | background: #fff; 70 | border: 1px solid #ccc; 71 | padding: 2px; 72 | max-width: 240px; 73 | min-width: 50px; 74 | z-index: 100; 75 | display: none; 76 | } 77 | #help { 78 | position: fixed; 79 | top: 10px; 80 | right: 10px; 81 | } 82 | #wikidatalogo { 83 | position: fixed; 84 | bottom: 10px; 85 | right: 10px; 86 | } 87 | table, td { 88 | border: 1px solid black; 89 | } 90 | #imageSources { 91 | position: fixed; 92 | bottom: 0px; 93 | right: 120px; 94 | } 95 | #displayArticle { 96 | position: fixed; 97 | top: 10px; 98 | right: 100px; 99 | } 100 | .buttonText { 101 | vertical-align: top; 102 | } 103 | .switch { 104 | position: relative; 105 | display: inline-block; 106 | width: 46px; 107 | height: 20px; 108 | } 109 | .switch input {display:none;} 110 | .slider { 111 | position: absolute; 112 | cursor: pointer; 113 | top: 0; 114 | left: 0; 115 | right: 0; 116 | bottom: 0; 117 | background-color: #ccc; 118 | -webkit-transition: .4s; 119 | transition: .4s; 120 | border-radius: 34px; 121 | } 122 | .slider:before { 123 | position: absolute; 124 | content: ""; 125 | height: 12px; 126 | width: 12px; 127 | left: 4px; 128 | bottom: 4px; 129 | background-color: #FAF9F4; 130 | -webkit-transition: .4s; 131 | transition: .4s; 132 | border-radius: 50%; 133 | } 134 | input:checked + .slider { 135 | background-color: #564A37; 136 | } 137 | input:focus + .slider { 138 | box-shadow: 0 0 1px #564A37; 139 | } 140 | input:checked + .slider:before { 141 | -webkit-transform: translateX(26px); 142 | -ms-transform: translateX(26px); 143 | transform: translateX(26px); 144 | } 145 | #imageSourcesList { 146 | position: fixed; 147 | bottom: 30px; 148 | right: 120px; 149 | border: 1px solid black; 150 | background-color: white; 151 | font-size: 60%; 152 | line-height: 60%; 153 | padding-left: 3px; 154 | padding-right: 3px; 155 | display: none; 156 | } 157 | #article { 158 | position: absolute; 159 | max-width: 450px; 160 | z-index: -100; 161 | display: none; 162 | } -------------------------------------------------------------------------------- /about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Everything is connected - About 6 | 7 | 8 | 9 |

Everything is connected

10 |

11 | Everything is connected. 12 | 13 | Knowledge is to understand these connections. 14 |

15 | Everything is connected is a knowledge game — 16 | a game relying on knowledge about the world in order to be solved. 17 | Like a quiz, and yet different. 18 |

19 | Everything is connected is also a puzzle. 20 | You get some pieces and have to figure out how they fit together. 21 | How they are connected. 22 | But unlike with a normal puzzle, whether or not two pieces fit together 23 | does not depend on the shape of the piece - afterall, all pieces are squares 24 | but it depends whether or not there is a known connection between them. 25 |

26 | What is a known connection? 27 | Each piece of the puzzle represents an entity in the world. 28 | It can be a country, a famous person, a song, a religion, or something else 29 | entirely. 30 | There are hundreds of different types of relations: 31 | for example, a person could be a citizen of a country, or 32 | the author of a song. 33 | A city can be the place of a birth of a person, or 34 | the capital of a country. 35 |

36 | Just like in every other puzzle, in order to place a piece somewhere on the 37 | board, it has to fit to all of its neighbours. 38 | Once all pieces are placed, the puzzle is solved. 39 |

40 |

[back to the game]

41 |

Credits

42 |

43 | Everything is connected was written by 44 | Denny Vrandečić. 45 |

46 | The data is based on 47 | Wikidata. 48 | All images are from 49 | Wikimedia Commons. 50 | The game is written using 51 | jQuery and 52 | jQuery UI. 53 | The code is available on 54 | Github, 55 | and contributors to the code are very welcome. 56 | Actually, if you want to take over the maintenance of the game, 57 | please contact me. 58 |

59 |

How does the game know about the relations?

60 |

61 | The game is based on Wikidata, the free and open knowledge base. 62 | Wikidata is like a machine-readable Wikipedia, although much younger. 63 | And like Wikipedia, Wikidata can be edited by anyone. 64 | Wikidata is incomplete and may contain errors. 65 | If you find errors in Wikidata while playing Everything is connected, 66 | you are welcome to join Wikidata and fix them. 67 |

68 |

Can I play this in other languages than English?

69 |

70 | Yes, you can. 71 |

72 | Just put the lang parameter to another language code. 73 | More than 300 languages are available. 74 | And if a certain puzzle piece doesn't have label in your language, you can 75 | just go to Wikidata and add it there. 76 |

77 | Examples: play in 78 | German, 79 | Uzbek, 80 | Croatian, 81 | Spanish, 82 | Chinese, 83 | Russian, or 84 | Georgian. 85 |

86 |

Can I create my own puzzles?

87 |

88 | Yes, you can. 89 |

90 | Probably the easiest way to do so is to take a pen and a paper, and first 91 | create a "solved" puzzle: 92 | make a grid, and fill every field you want to fill. 93 | Not every field has to be filled - the result does not have to be a completely 94 | filled square. 95 |

96 | Example: 97 | 98 | 99 | 100 |
- Jackie KennedyNew York City
HarvardJFKUSA
101 |

102 | Note that you can only use entities for the puzzle that are available in 103 | Wikidata, and only relations that are known to Wikidata will be counted as 104 | valid known relations. 105 |

106 | Now go to Wikidata, and for each of the entities find their corresponding Q-Id. 107 | Write them down in the grid. 108 |

109 | Example: 110 | 111 | 112 | 113 | 117 | 121 | 122 | 123 | 127 | 131 | 135 | 136 |
- Q0 114 | Jackie Kennedy 115 | Q165421 116 | 118 | New York City 119 | Q60 120 |
124 | Harvard 125 | Q13371 126 | 128 | JFK 129 | Q9696 130 | 132 | USA 133 | Q30 134 |
137 |

138 | Now start on the top line of your grid, and write the Q-Id consecutively down. 139 | Once one line is finished, close it with a /, and then continue with the next 140 | line. 141 | If you have a gap in your grid, just put a Q0 there. 142 |

143 | Example: 144 | for the above example, we would write down: 145 | Q0Q165421Q60/Q13371Q9696Q30. 146 |

147 | Finally, decide which of the tiles should already be preset and fixed - if any - 148 | and add a + just right behind them. 149 |

150 | Example: 151 | we could decide that Harvard will be preset, so we add a + just after Q13371: 152 | Q0Q165421Q60/Q13371+Q9696Q30. 153 |

154 | The resulting string can be used as the board parameter on the URL for the game. 155 | You can then send the URL to others to try to solve your puzzle. 156 |

157 | Example: 158 | our example would be accessible at 159 | 160 | https://tools.wmflabs.org/everythingisconnected/index.html?board=Q0Q165421Q60/Q13371+Q9696Q30 161 |
162 | You can even switch the language by adding a language parameter too, say, to Greek: 163 | 164 | https://tools.wmflabs.org/everythingisconnected/index.html?board=Q0Q165421Q60/Q13371+Q9696Q30&lang=el 165 | . 166 |

167 | If you create levels you like, share them on 168 | 169 | the Wikidata list of levels. 170 |

171 |

Possibly unsolvable puzzles

172 |

173 | In order to minimize a frustrating playing experience, the game checks at the 174 | beginning of a level whether the game is actual still solvable with the 175 | original solution. 176 | If it is not, the background will change to red, and a warning message will 177 | be displayed. 178 |

179 | Because Wikidata can and does change all the time, a puzzle that once was 180 | solvable could actually suddenly require a different solution, or even become 181 | unsolvable at all. 182 |

183 | Sometimes this is due to errors being removed from Wikidata, on which the 184 | puzzle was relying on, sometimes this is due to changes in the modeling of 185 | Wikidata, and sometimes this is due to correct facts in Wikidata being removed. 186 | If the latter, feel free to go to Wikidata and join the editing community in 187 | order to put the correct data back in. 188 |

189 | Feel free to mark puzzles that are unsolvable as such on 190 | 191 | the Wikidata list of levels in case you arrived at the puzzle through that page. 192 |

193 | Note that a puzzle that you have been warned about can still have a solution - 194 | but a different one than the originally envisioned ones. 195 | The game does not check for all possible solutions, merely if the original 196 | solution is still applicable. 197 |

198 |

[back to the game]

199 | 200 | 201 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | /** Copyright 2016 Google Inc. 2 | /* 3 | /* Licensed under the Apache License, Version 2.0 (the "License"); 4 | /* you may not use this file except in compliance with the License. 5 | /* You may obtain a copy of the License at 6 | /* 7 | /* http://www.apache.org/licenses/LICENSE-2.0 8 | /* 9 | /* Unless required by applicable law or agreed to in writing, software 10 | /* distributed under the License is distributed on an "AS IS" BASIS, 11 | /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | /* See the License for the specific language governing permissions and 13 | /* limitations under the License. 14 | */ 15 | (function ($) {$(function() { 16 | /** TODOs 17 | / * editor for new puzzles 18 | / * display direction of the relation (suggestion mkroetzsch) 19 | / * todos in code 20 | */ 21 | 22 | evil = {}; // just a global for debugging reasons, should not be used in code 23 | 24 | var fieldSize = 100; 25 | var topSpace = 5; 26 | var leftSpace = 5; 27 | var wiggleSpace = 20; 28 | var finished = false; 29 | 30 | var shuffle = function(array) { 31 | // Knuth shuffle algorithm 32 | var i = array.length, t, r; 33 | while (0 !== i) { 34 | r = Math.floor(Math.random() * i); 35 | i -= 1; 36 | t = array[i]; 37 | array[i] = array[r]; 38 | array[r] = t; 39 | } 40 | return array; 41 | }; 42 | var createBoard = function(lang, board) { 43 | $.each(board.field, function(lineindex, line) { 44 | $.each(line, function(rowindex, field) { 45 | var tileclass = "field"; 46 | var qid = ""; 47 | if (!board.field[lineindex][rowindex].exists) { return; } 48 | if (board.field[lineindex][rowindex].fixed) { 49 | qid = board.field[lineindex][rowindex].current; 50 | tileclass += " fixed"; 51 | } 52 | var pos = 'l' + lineindex + 'r' + rowindex; 53 | $("#board").append( 54 | '
' + qid + '
' 55 | ); 56 | $('#' + pos).css({top: lineindex*fieldSize+topSpace, left: rowindex*fieldSize+leftSpace}); 57 | $('#' + pos).data('qid', qid); 58 | }); 59 | }); 60 | $("#board").width(board.maxWidth*fieldSize + 5); 61 | $("#board").height(board.maxHeight*fieldSize + 5); 62 | 63 | shuffle(board.deck); 64 | 65 | // TODO: refactor the layouting code in the following lines 66 | // the following lines are trying to determine where the best space for the 67 | // article and the deck is. This code should be refactored, it is 68 | // unreadable and has grown a bit without a plan. Better to rewrite it 69 | // entirely. Layouting is hard. It is entirely possible that we can just 70 | // let HTML do all the formatting somehow. 71 | var leftshift = 0; 72 | var topshift = 0; 73 | if (($(window).width()-board.maxWidth*fieldSize)>($(window).height()-board.maxHeight*fieldSize)) { 74 | leftshift = board.maxWidth; 75 | } else { 76 | topshift = board.maxHeight; 77 | } 78 | var articleleft = leftshift; 79 | var articletop = topshift; 80 | if ($(window).width()>(board.maxWidth*fieldSize+200)) { 81 | articleleft = board.maxWidth; 82 | articletop = 0; 83 | } 84 | var tilesPerLine = Math.floor($(window).width()/fieldSize)-1; 85 | var neededLines = Math.ceil(board.deck.length / tilesPerLine); 86 | if ($(window).height()>(neededLines+board.maxHeight+1)*fieldSize) { 87 | topshift = board.maxHeight; 88 | leftshift = 0; 89 | } else { 90 | tilesPerLine = board.maxWidth; 91 | } 92 | if (articleleft>0) { 93 | $("#article").css({left: (articleleft+0.5)*fieldSize+leftSpace}); 94 | } else { 95 | $("#article").css({top: (articletop+1.5)*fieldSize+topSpace}); 96 | } 97 | $.each(board.deck, function(index, qid) { 98 | $("#board").append('
' + qid + '
'); 99 | $('#' + qid).css({ 100 | left: ((index % tilesPerLine) +leftshift)*fieldSize+leftSpace+wiggleSpace + Math.floor(Math.random()*wiggleSpace), 101 | top: (Math.floor(index/tilesPerLine)+topshift)*fieldSize+topSpace+wiggleSpace + Math.floor(Math.random()*wiggleSpace) 102 | }); 103 | $('#' + qid).data('qid', qid); 104 | }); 105 | // end of the code that has the weird layouting stuff in it. 106 | 107 | var kb = {}; 108 | 109 | $( ".side" ).draggable({ 110 | start: function(event, ui) { 111 | if (!finished) return; 112 | var qid = $(this).attr('id'); 113 | if (board.pieces[qid]!=null) { 114 | var y = board.pieces[qid][0]; 115 | var x = board.pieces[qid][1]; 116 | board.field[y][x].current = null; 117 | board.pieces[qid] = null; 118 | } 119 | checkBoard(board, lang, kb); 120 | } 121 | }); 122 | $( ".field" ).droppable({ 123 | accept: ".side", 124 | drop: function(event, ui) { 125 | if (!finished) return; 126 | var pos = $(this).attr('id').substring(1).split('r'); 127 | var y = parseInt(pos[0]); 128 | var x = parseInt(pos[1]); 129 | if (board.field[y][x].current==null) { 130 | $(ui.draggable).css($(this).position()); 131 | var qid = ui.draggable.attr('id'); 132 | board.field[y][x].current = ui.draggable.attr('id'); 133 | board.pieces[qid] = [y, x]; 134 | } 135 | checkBoard(board, lang, kb); 136 | } 137 | }); 138 | 139 | var articles = {}; 140 | loadBoardEntities(kb, lang, board, articles); 141 | 142 | var displayArticle = function(event) { 143 | var id = $(event.target).data('qid'); 144 | if (id in articles) { 145 | $("#article").html(articles[id]); 146 | } 147 | }; 148 | $(".fixed").mouseenter(displayArticle); 149 | $(".side").mouseenter(displayArticle); 150 | }; 151 | var loadExtracts = function(toLoad, qids, lang, articles) { 152 | var loadNow = toLoad.slice(0, 16); 153 | var loadLater = toLoad.slice(16); 154 | $.ajax({ 155 | dataType: "jsonp", 156 | url: 'https://en.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&exsentences=3&exlimit=20&exintro=1&titles=' + loadNow.join('|') 157 | }).done(function ( response ) { 158 | $.each(response.query.pages, function(index, entity) { 159 | if (typeof(entity.extract) == 'undefined') return; 160 | if (entity.extract=='') return; 161 | var text = entity.extract; 162 | text += '[Wikipedia]'; 163 | articles[qids[entity.title]] = text; 164 | }); 165 | if (loadLater.length > 0) { 166 | loadExtracts(loadLater, qids, lang, articles); 167 | } 168 | }); 169 | }; 170 | var loadArticles = function(kb, args) { 171 | setFinished(); 172 | var lang = args.lang; 173 | var articles = args.articles; 174 | var wiki = lang + 'wiki'; 175 | var titles = {}; 176 | var qids = {}; 177 | var toLoad = []; 178 | $.each(kb, function(index, entity) { 179 | if (index[0]!='Q') return; 180 | if (!('sitelinks' in entity)) return; 181 | if (!(wiki in entity.sitelinks)) return; 182 | if (!('title' in entity.sitelinks[wiki])) return; 183 | qids[entity.sitelinks[wiki].title] = index; 184 | toLoad.push(entity.sitelinks[wiki].title); 185 | }); 186 | loadExtracts(toLoad, qids, lang, articles); 187 | }; 188 | var urlParam = function(name) { 189 | var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); 190 | if (results==null) { 191 | return null; 192 | } else { 193 | return results[1] || 0; 194 | } 195 | }; 196 | var initLanguage = function() { 197 | var lang = urlParam('lang'); 198 | if (lang==null) { 199 | lang = 'en'; 200 | } 201 | return lang; 202 | }; 203 | var validateBoard = function(param) { 204 | return /^(Q[0-9]*\+?\/?)*$/.test(param); 205 | }; 206 | var initBoard = function() { 207 | var boardParam = urlParam('board'); 208 | if (boardParam!=null && !validateBoard(boardParam)) { 209 | console.log("Using default board as parameter board is invalid: " + boardParam); 210 | boardParam = null; 211 | } 212 | if (boardParam==null) { 213 | // default starting board 214 | boardParam = 'Q7186+Q1622272Q60025/Q5Q9438Q868/Q1067Q40185Q8409+'; 215 | } 216 | var board = {}; 217 | board.initstring = boardParam; 218 | var lines = board.initstring.split('/'); 219 | board.deck = []; 220 | board.pieces = {}; 221 | board.field = $.map(lines, function(line) { 222 | return [$.map(line.substring(1).split('Q'), function(value) { 223 | var field = {}; 224 | field.exists = (value!='0'); 225 | if (!field.exists) { 226 | field.solution = null; 227 | field.current = null; 228 | field.fixed = null; 229 | return field; 230 | } 231 | field.fixed = (value.slice(-1)=='+'); 232 | if (field.fixed) { 233 | field.solution = 'Q' + value.slice(0, -1); 234 | field.current = field.solution; 235 | } else { 236 | field.solution = 'Q' + value; 237 | field.current = null; 238 | board.deck.push(field.solution); 239 | board.pieces[field.solution] = null; 240 | } 241 | return field; 242 | })]; 243 | }); 244 | board.maxHeight = lines.length; 245 | board.maxWidth = Math.max.apply(null, $.map(board.field, function(line) { return line.length; })); 246 | for (y = 0; y < board.maxHeight; y++) 247 | for (x = 0; x < board.maxWidth; x++) { 248 | if (x>=board.field[y].length) { 249 | board.field[y][x] = { exists: false, solution: null, current: null, fixed: null } 250 | } 251 | if (board.field[y][x].current!=null) 252 | board.pieces[board.field[y][x].current] = [y, x]; 253 | } 254 | return board; 255 | }; 256 | var showConnection = function(y1, x1, y2, x2, p, kb, language) { 257 | if (y1==y2) { 258 | var y = topSpace+(y1+0.5)*fieldSize-15; 259 | var x = leftSpace+(x1+1)*fieldSize-15; 260 | } 261 | if (x1==x2) { 262 | var y = topSpace+(y1+1)*fieldSize-15; 263 | var x = leftSpace+(x1+0.5)*fieldSize-15; 264 | } 265 | var elem = $('
?
'); 266 | if (p!=false) { 267 | var proplabel = getLabel(kb[p], language); 268 | elem = $('
 ' + proplabel + '
'); 269 | // the following is to fixup popups on mobile 270 | elem.attr("data-hide", false); 271 | elem.click(function () { 272 | var $popup = $(this).find(".popup"); 273 | if ($popup.attr("data-hide") === "false") { 274 | $popup.show(); 275 | } 276 | $popup.attr("data-hide", false); 277 | }); 278 | elem.click(function () { $(this).attr("data-hide",true); }); 279 | $(document).mouseup(function () { $(".popup").hide(); }); 280 | elem.mouseenter(function () { $(this).find(".popup").show(); }); 281 | elem.mouseleave(function () { $(this).find(".popup").hide(); }); 282 | } 283 | elem.css({top: y, left: x}); 284 | $("#board").append(elem); 285 | }; 286 | var clearConnections = function() { 287 | $(".connection").remove(); 288 | }; 289 | var loadEntities = function(toLoad, entities, callbackFunction, argumentsToCallback) { 290 | var loadNow = toLoad.slice(0, 48); 291 | var loadLater = toLoad.slice(48); 292 | $.ajax({ 293 | dataType: "jsonp", 294 | url: 'https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&ids=' + toLoad.join('|') 295 | }).done(function ( response ) { 296 | $.each(response.entities, function(index, entity) { 297 | entities[index] = entity; 298 | }); 299 | if (loadLater.length > 0) { 300 | loadEntities(loadLater, entities, callbackFunction, argumentsToCallback); 301 | } else { 302 | callbackFunction(entities, argumentsToCallback); 303 | } 304 | }); 305 | }; 306 | var setFinished = function() { 307 | finished=true; 308 | }; 309 | var loadProperties = function(entities, args) { 310 | setFinished(); 311 | var properties = []; 312 | $.each(args.kb, function(index, item) { 313 | $.each(item.claims, function(prop, values) { 314 | if ($.inArray(prop, properties)==-1) { 315 | properties.push(prop); 316 | } 317 | }); 318 | }); 319 | loadEntities(properties, args.kb, loadArticles, {lang: args.language, articles: args.articles}); 320 | paintTiles(args.board, args.language, args.kb, args.articles); 321 | solvableBoard(args.board, args.kb) 322 | }; 323 | var loadBoardEntities = function(kb, language, board, articles) { 324 | boardEntities = []; 325 | for (y=0;y' + filename + '

') 372 | $.getJSON('https://commons.wikimedia.org/w/api.php?callback=?', { 373 | action: 'query' , 374 | formatversion: 2, 375 | prop: 'imageinfo', 376 | iiprop: 'url' , 377 | iilimit: 1, 378 | iiurlwidth: 80, 379 | titles: 'File:' + filename, 380 | format: 'json' 381 | }, function(commonsresponse) { 382 | var url = commonsresponse.query.pages[0].imageinfo[0].thumburl; 383 | $(tile).css('background-image', 'url(' + url + ')'); 384 | }); 385 | }; 386 | var paintTiles = function(board, language, kb, articles) { 387 | for (y=0;y ' + d + '

'; 401 | if ($("#article").html()=="") { $("#article").html(articles[f.solution]); } 402 | } 403 | $(tile + ' span').text(l); 404 | setImage(kb[f.solution], tile); 405 | } 406 | }; 407 | var hasClaimObject = function(s, o, kb) { 408 | var connection = false; 409 | $.each(kb[s].claims, function(p, v) { 410 | $.each(v, function(i, v) { 411 | if (connection!=false) return; 412 | if (v.mainsnak.datatype=="wikibase-item") 413 | if (v.mainsnak.snaktype=="value") 414 | if (v.mainsnak.datavalue.value.id == o) 415 | connection = p; 416 | }); 417 | }); 418 | return connection; 419 | }; 420 | var fits = function(q1, q2, kb) { 421 | return hasClaimObject(q1, q2, kb) || hasClaimObject(q2, q1, kb); 422 | }; 423 | var checkBoard = function(board, language, kb) { 424 | clearConnections(); 425 | var allSet = true; 426 | var allFit = true; 427 | for (y=0;y[List of levels]

'); 460 | } 461 | }; 462 | var solvableBoard = function(board, kb) { 463 | var allFit = true; 464 | for (y=0;yWarning! This level might be unsolvable [see more]

'); 482 | } 483 | }; 484 | createBoard(initLanguage(), initBoard()); 485 | 486 | $('#imageSources').click(function() { $('#imageSourcesList').toggle(); }); 487 | $('#articleSwitch').click(function() { $('#article').toggle(); }); 488 | });}(jQuery)); 489 | --------------------------------------------------------------------------------