├── .gitignore ├── .npmignore ├── demo ├── src │ ├── react-app-env.d.ts │ ├── setupTests.js │ ├── App.test.js │ ├── reportWebVitals.js │ ├── index.css │ ├── index.js │ ├── App.css │ ├── App.js │ └── logo.svg ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── stages │ │ ├── TX Plant.png │ │ ├── TX Props.png │ │ ├── TX Struct.png │ │ ├── TX Shadow Plant.png │ │ ├── TX Tileset Wall.png │ │ ├── TX Tileset Grass.png │ │ ├── TX Shadow Plant.tsx │ │ ├── TX Tileset Grass.tsx │ │ ├── TX Plant.tsx │ │ ├── TX Props.tsx │ │ ├── TX Struct.tsx │ │ ├── TX Tileset Wall.tsx │ │ └── map.tmx │ ├── manifest.json │ └── index.html ├── .gitignore └── package.json ├── img ├── example.png └── layers-pane.png ├── src ├── TilemapContext.js ├── useMap.js ├── useObjects.js ├── useSpawnPoint.js ├── useInteractables.js ├── index.js ├── useTiles.js ├── useCollisions.js ├── useTilemapLoader.js ├── Layer.jsx ├── Tilemap.jsx └── getSprite.js ├── .editorconfig ├── LICENSE ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | src/ -------------------------------------------------------------------------------- /demo/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /img/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/img/example.png -------------------------------------------------------------------------------- /demo/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /img/layers-pane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/img/layers-pane.png -------------------------------------------------------------------------------- /demo/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/favicon.ico -------------------------------------------------------------------------------- /demo/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/logo192.png -------------------------------------------------------------------------------- /demo/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/logo512.png -------------------------------------------------------------------------------- /demo/public/stages/TX Plant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/stages/TX Plant.png -------------------------------------------------------------------------------- /demo/public/stages/TX Props.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/stages/TX Props.png -------------------------------------------------------------------------------- /demo/public/stages/TX Struct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/stages/TX Struct.png -------------------------------------------------------------------------------- /demo/public/stages/TX Shadow Plant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/stages/TX Shadow Plant.png -------------------------------------------------------------------------------- /demo/public/stages/TX Tileset Wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/stages/TX Tileset Wall.png -------------------------------------------------------------------------------- /demo/public/stages/TX Tileset Grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vocksel/react-pixi-tilemap/HEAD/demo/public/stages/TX Tileset Grass.png -------------------------------------------------------------------------------- /src/TilemapContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | const TilemapContext = createContext() 4 | 5 | export default TilemapContext 6 | -------------------------------------------------------------------------------- /src/useMap.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react" 2 | import TilemapContext from './TilemapContext' 3 | 4 | const useMap = () => { 5 | const { map } = useContext(TilemapContext) 6 | return map 7 | } 8 | 9 | export default useMap -------------------------------------------------------------------------------- /demo/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /demo/public/stages/TX Shadow Plant.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/public/stages/TX Tileset Grass.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = crlf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.json] 15 | indent_size = 2 -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /demo/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/useObjects.js: -------------------------------------------------------------------------------- 1 | import { useContext, useMemo } from "react" 2 | import TilemapContext from "./TilemapContext" 3 | 4 | const useObjects = () => { 5 | const { map } = useContext(TilemapContext) 6 | 7 | const objects = useMemo(() => map.layers 8 | .filter(layer => layer.type === 'object') 9 | .map(layer => layer.objects) 10 | .flat(), 11 | [ map ]) 12 | 13 | return objects 14 | } 15 | 16 | export default useObjects -------------------------------------------------------------------------------- /demo/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | overflow: hidden; 5 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 6 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 7 | sans-serif; 8 | -webkit-font-smoothing: antialiased; 9 | -moz-osx-font-smoothing: grayscale; 10 | } 11 | 12 | code { 13 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 14 | monospace; 15 | } 16 | -------------------------------------------------------------------------------- /src/useSpawnPoint.js: -------------------------------------------------------------------------------- 1 | import { Point } from "pixi.js" 2 | import { useMemo } from "react" 3 | import useObjects from "./useObjects" 4 | 5 | const useSpawnPoint = () => { 6 | const objects = useObjects() 7 | 8 | const point = useMemo(() => { 9 | const spawn = objects.find(object => object.name === 'Spawn') 10 | return new Point(spawn.x + spawn.width / 2, spawn.y + spawn.height / 2) 11 | }) 12 | 13 | return point 14 | } 15 | 16 | export default useSpawnPoint 17 | -------------------------------------------------------------------------------- /src/useInteractables.js: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import useObjects from './useObjects' 3 | 4 | const useInteractableObjects = () => { 5 | const objects = useObjects() 6 | 7 | return useMemo(() => { 8 | const interactables = [] 9 | 10 | for (const object of objects) { 11 | if (object.properties.isInteractable) { 12 | interactables.push(object) 13 | } 14 | } 15 | 16 | return interactables 17 | }, [ objects ]) 18 | } 19 | 20 | export default useInteractableObjects -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Tilemap from './Tilemap' 2 | import useTilemapLoader from './useTilemapLoader' 3 | import useMap from './useMap' 4 | import useSpawnPoint from './useSpawnPoint' 5 | import useCollisions from './useCollisions' 6 | import useInteractables from './useInteractables' 7 | import useObjects from './useObjects' 8 | import useTiles from './useTiles' 9 | 10 | export { 11 | Tilemap, 12 | useTilemapLoader, 13 | useInteractables, 14 | useMap, 15 | useSpawnPoint, 16 | useCollisions, 17 | useObjects, 18 | useTiles, 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /demo/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/useTiles.js: -------------------------------------------------------------------------------- 1 | import { useContext, useEffect, useState } from "react" 2 | import TilemapContext from "./TilemapContext" 3 | 4 | const useTiles = () => { 5 | const { map } = useContext(TilemapContext) 6 | const [tiles, set] = useState([]) 7 | 8 | useEffect(() => { 9 | if (map) { 10 | const newTiles = map.layers 11 | .filter(layer => layer.type === 'tile') 12 | .map(layer => layer.tiles) 13 | .flat() 14 | .filter(tile => tile !== null) 15 | 16 | set(newTiles) 17 | } 18 | }, [ map ]) 19 | 20 | return tiles 21 | } 22 | 23 | export default useTiles -------------------------------------------------------------------------------- /demo/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /demo/src/App.js: -------------------------------------------------------------------------------- 1 | import { Stage, Sprite } from '@inlet/react-pixi'; 2 | import { Texture } from '@pixi/core'; 3 | import { Tilemap, useTilemapLoader } from 'react-pixi-tilemap' 4 | 5 | const tilemape = process.env.PUBLIC_URL + '/stages/map.tmx' 6 | 7 | const App = () => { 8 | const map = useTilemapLoader(tilemape) 9 | 10 | return ( 11 | 12 | 13 | {/* These sprites show off the layering order */} 14 | 15 | 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@inlet/react-pixi": "^6.5.4", 7 | "@testing-library/jest-dom": "^5.11.4", 8 | "@testing-library/react": "^11.1.0", 9 | "@testing-library/user-event": "^12.1.10", 10 | "react-pixi-tilemap": "../", 11 | "pixi.js": "^6.0.4", 12 | "react": "^17.0.2", 13 | "react-dom": "^17.0.2", 14 | "react-scripts": "4.0.3", 15 | "web-vitals": "^1.0.1" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2021 David Minnerly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /src/useCollisions.js: -------------------------------------------------------------------------------- 1 | import { Rectangle } from "pixi.js" 2 | import { useContext, useMemo } from "react" 3 | import TilemapContext from "./TilemapContext" 4 | 5 | const useCollisions = () => { 6 | const { map } = useContext(TilemapContext) 7 | 8 | const collisions = useMemo(() => { 9 | return map.layers 10 | .filter(layer => layer.type === 'tile') 11 | .map(layer => { 12 | const rects = [] 13 | 14 | for (const tile of layer.tiles) { 15 | if (tile) { 16 | const { objectGroups } = tile 17 | 18 | if (objectGroups.length > 0) { 19 | for (const rectangle of objectGroups) { 20 | const { x, y, width, height } = rectangle 21 | rects.push(new Rectangle(tile.x + x, tile.y + y, width, height)) 22 | } 23 | } 24 | } 25 | } 26 | 27 | return rects 28 | }) 29 | .flat() 30 | }, [ map ]) 31 | 32 | return collisions 33 | } 34 | 35 | export default useCollisions -------------------------------------------------------------------------------- /src/useTilemapLoader.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | import tmx from 'tmx-parser' 3 | 4 | const useTilemapLoader = (tilemapPath) => { 5 | const [map, setMap] = useState(null) 6 | 7 | useEffect(() => { 8 | tmx.parseFile(tilemapPath, (err, map) => { 9 | if (err) throw err 10 | 11 | // Add (x,y) coordinates to each tile so it is easy to align collision 12 | // rectangles later. 13 | map.layers = map.layers.map(layer => { 14 | return { 15 | ...layer, 16 | tiles: layer.tiles?.map((tile, index) => { 17 | const x = (index % map.width) * map.tileWidth 18 | const y = Math.floor(index / map.width) * map.tileHeight 19 | const width = map.tileWidth 20 | const height = map.tileHeight 21 | 22 | return { ...tile, x, y, width, height} 23 | }) 24 | } 25 | }) 26 | 27 | map.path = tilemapPath 28 | 29 | setMap(map) 30 | }) 31 | }, [ tilemapPath ]) 32 | 33 | return map 34 | } 35 | 36 | export default useTilemapLoader 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-pixi-tilemap", 3 | "version": "2.0.2", 4 | "description": "Use maps created with Tiled in your React-based Pixi.js games", 5 | "source": "src/index.js", 6 | "main": "dist/index.js", 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "dev": "cd demo && yarn start", 12 | "watch": "microbundle watch --jsx React.createElement", 13 | "start": "concurrently \"yarn:watch\" \"yarn:dev\"", 14 | "build": "microbundle build --jsx React.createElement", 15 | "test": "echo \"Error: no test specified\" && exit 1" 16 | }, 17 | "keywords": [ 18 | "react", 19 | "pixi", 20 | "tiled", 21 | "tmx", 22 | "tilemap", 23 | "tileset" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/vocksel/react-pixi-tilemap" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/vocksel/react-pixi-tilemap/issues" 31 | }, 32 | "author": "David Minnerly", 33 | "license": "MIT", 34 | "peerDependencies": { 35 | "@inlet/react-pixi": ">=6.5.2", 36 | "pixi.js": ">=6.0.4", 37 | "react": ">=17.0.2" 38 | }, 39 | "dependencies": { 40 | "tmx-parser": "github:eioo/node-tmx-parser" 41 | }, 42 | "devDependencies": { 43 | "concurrently": "^6.2.0", 44 | "microbundle": "^0.13.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Layer.jsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react' 2 | import { Container } from "@inlet/react-pixi" 3 | import getSprite from './getSprite' 4 | 5 | const getTileSprites = (layer, map) => { 6 | const sprites = [] 7 | 8 | for (let y = 0; y < map.height; y++) { 9 | for (let x = 0; x < map.width; x++) { 10 | const i = x + y * map.width 11 | const tile = layer.tiles[i] 12 | 13 | if (tile?.gid > 0) { 14 | sprites.push(getSprite('tile', tile, map)) 15 | } 16 | } 17 | } 18 | 19 | return sprites 20 | } 21 | 22 | const getObjectSprites = (layer, map) => { 23 | return layer.objects.map(object => { 24 | if (object.gid) { 25 | return getSprite('object', object, map) 26 | } 27 | }) 28 | } 29 | 30 | const Layer = ({ layer, map }) => { 31 | if (!layer.visible) { 32 | return null 33 | } 34 | 35 | const sprites = useMemo(() => { 36 | if (layer.type === 'tile') { 37 | return getTileSprites(layer, map) 38 | } else if (layer.type === 'object') { 39 | return getObjectSprites(layer, map) 40 | } 41 | }, [ layer ] ) 42 | 43 | return 44 | {sprites} 45 | 46 | } 47 | 48 | export default Layer 49 | -------------------------------------------------------------------------------- /src/Tilemap.jsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo, useState } from 'react' 2 | import { Container } from '@inlet/react-pixi' 3 | import TilemapContext from './TilemapContext' 4 | import Layer from './Layer' 5 | 6 | const Tilemap = ({ map, children, ...props }) => { 7 | const [hasForeground, setHasForeground] = useState(false) 8 | 9 | const layers = useMemo(() => { 10 | return map?.layers.map((layer, index) => { 11 | const { name } = layer 12 | if (name === 'Foreground') { 13 | setHasForeground(true) 14 | return children 15 | } else { 16 | return 17 | } 18 | }) 19 | }, [ map, children ]) 20 | 21 | // Only render once the map is loaded so that our hooks don't need to 22 | // conditionally check if anything in TilemapContext exists. 23 | if (map) { 24 | return 25 | 26 | {layers} 27 | 28 | {/* If there's no foreground layer specified in the map, we simply render the children on top */} 29 | {!hasForeground && children} 30 | 31 | 32 | } else { 33 | return null 34 | } 35 | 36 | } 37 | 38 | export default Tilemap 39 | -------------------------------------------------------------------------------- /src/getSprite.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import { Rectangle, Texture } from 'pixi.js' 3 | import { Sprite } from "@inlet/react-pixi" 4 | import React from "react" 5 | 6 | const getTilesetForGID = (gid, tilesets) => { 7 | let result 8 | for (const tileset of tilesets) { 9 | if (gid >= tileset.firstGid) { 10 | result = tileset 11 | } 12 | } 13 | return result 14 | } 15 | 16 | const getTileTexture = (tile, map, tileset) => { 17 | const { image, tileHeight, tileWidth } = tileset 18 | const spriteIndex = tile.gid - tileset.firstGid 19 | 20 | const x = (spriteIndex % (image.width / tileWidth)) * tileWidth 21 | const y = Math.floor(spriteIndex / (image.height / tileHeight)) * tileHeight 22 | 23 | const rootDir = path.dirname(map.path) 24 | const baseTexture = Texture.from(`${rootDir}/${tileset.image.source}`) 25 | 26 | return new Texture(baseTexture, new Rectangle(x, y, tileHeight, tileWidth)) 27 | } 28 | 29 | const getTileSprite = (tileType, tile, map) => { 30 | const tileset = getTilesetForGID(tile.gid, map.tileSets) 31 | 32 | if (tileset) { 33 | const { x, width, height } = tile 34 | const texture = getTileTexture(tile, map, tileset) 35 | 36 | // Objects are bottom aligned for some reason. This pushes them up so they align with the rest of the tilemap. 37 | let y = tile.y 38 | if (tileType === 'object') { 39 | y -= height 40 | } 41 | 42 | return 49 | } 50 | } 51 | 52 | export default getTileSprite 53 | -------------------------------------------------------------------------------- /demo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /demo/public/stages/TX Plant.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /demo/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/public/stages/TX Props.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-pixi-tilemap 2 | 3 | This package allows you to easily make use of levels created with [Tiled](https://www.mapeditor.org/) in your React and Pixi based games. 4 | 5 | Supports embedded and external tilesets, collisions, child layering, and comes with a bunch of different hooks to work with tiles and objects from within your components. 6 | 7 | ![Screenshot of the demo map](img/example.png) 8 | 9 | ## Install 10 | 11 | ```sh 12 | $ npm install react-pixi-tilemap 13 | # Or 14 | $ yarn add react-pixi-tilemap 15 | ``` 16 | 17 | ## Usage 18 | 19 | Your `.tmx` files, and their associated `.tsx` and atlas files, should be in a static location, such as the `public` folder if you are using create-react-app. This makes it easy for the Tilemap component to find assets used in the map. 20 | 21 | Using the component is dead simple. Simply load your map and pass it into the Tilemap component. 22 | 23 | ```js 24 | import { Tilemap, useTilemapLoader } from 'react-pixi-tilemap' 25 | 26 | const tilemap = process.env.PUBLIC_URL + '/stages/map.tmx' 27 | 28 | const App = (props) => { 29 | const map = useTilemapLoader(tilemap) 30 | 31 | return ( 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ) 40 | } 41 | ``` 42 | 43 | The return value of `useTilemapLoader` is an Object represented by [TMX Map Format#map](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#map). Make sure to look over those docs to learn more about what properties you have access to. 44 | 45 | Be advised that you should not use a typical `import` statement. If you `import map from './map.tmx'`, Webpack (or similar build system) will take your .tmx file away from your tilesets, which breaks the Tilemap component's discovery. As such, keeping your tilemaps and tilesets in a static location will give you the best results. 46 | 47 | Your tilesets can either be saved as `.tsx` files, or embedded in the `.tmx` file itself. Either works with this package. Keep in mind however that you _cannot_ save your tilesets as their `.json` equivalents. This seems to be an issue with tmx-parser. 48 | 49 | ## Example 50 | 51 | Check out the [demo project](demo) for an example of how this all comes together. Be sure to open up the [map.tmx]() file in Tiled and explore around. 52 | 53 | To get setup, run the following commands: 54 | 55 | ```sh 56 | $ cd demo 57 | $ yarn install 58 | $ yarn start 59 | ``` 60 | 61 | ## Foreground Layer 62 | 63 | Adding a `Foreground` layer to your `.tmx` file determines where children of the Tilemap component are rendered. Without this layer, children are rendered on top of the map. If you want children to appear above some layers, and behind others, then make sure to include this layer. The order of the Foreground layer in Tiled's `Layer` pane controls where the children are rendered. 64 | 65 | ![Screenshot of the Layers pane in Tiled](img/layers-pane.png) 66 | 67 | ## Hooks 68 | 69 | **`useCollisions()`** 70 | 71 | Returns a flat list of Pixi.js Rectangle instances that represent the collisions defined in the `.tmx` file. These can be configured with Tiled's [Collision Editor](https://doc.mapeditor.org/en/stable/manual/editing-tilesets/#tile-collision-editor). 72 | 73 | ```js 74 | const collisions = useCollisions() 75 | ``` 76 | 77 | **`useInteractables()`** 78 | 79 | Any object that has a bool `isInteractable` custom property in Tiled will be picked up by this hook. This allows you to easily define objects in the game (such as NPCs, items on the ground, etc.) as something the user can interact with, and use them in your code. 80 | 81 | ```js 82 | const interactables = useInteractables() 83 | ``` 84 | 85 | **`useMap()`** 86 | 87 | Returns the `map` property passed into Tilemap. This can be helpful if you need to access metadata about the map, or if you need to write a hook that is not included in this package. 88 | 89 | See [TMX Map Format#map](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#map). 90 | 91 | ```js 92 | const map = useMap() 93 | ``` 94 | 95 | **`useObjects()`** 96 | 97 | Returns a flat list of every object across every layer. 98 | 99 | See [TMX Map Format#object](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#object) 100 | 101 | ```js 102 | const objects = useObjects() 103 | ``` 104 | 105 | **`useSpawnPoint()`** 106 | 107 | This hook is fairly specific, but if you add an object named `Spawn`, this hook will return it for you. This makes it easy to setup a spawn location for player characters. 108 | 109 | **`useTilemapLoader(tilemapPath)`** 110 | 111 | This hook is what you use to load your .tmx map before passing it into the Tilemap component. 112 | 113 | **`useTiles()`** 114 | 115 | Returns a flat array of every tile in the map. 116 | 117 | See [TMX Map Format#tile](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#tile). 118 | 119 | ## Credits 120 | 121 | Thanks to Cainos' for their awesome [Pixel Art Top Down - Basic](https://cainos.itch.io/pixel-art-top-down-basic) tiles. 122 | 123 | Also very big shoutout to the following repos that were very invaluable in figuring out how to create this package. 124 | 125 | - [Reynau/tiled-to-pixi](https://github.com/Reynau/tiled-to-pixi) 126 | - [knervous/tiled-pixi-react](https://github.com/knervous/tiled-pixi-react) 127 | 128 | ## Developing 129 | 130 | Run the following commands from the root directory to install all dependencies, and get setup with a dev environment that will live-reload as you make changes to the package. 131 | 132 | ```sh 133 | $ yarn install 134 | $ yarn link 135 | $ cd demo 136 | $ yarn link react-pixi-tilemap 137 | $ yarn install 138 | $ cd .. 139 | $ yarn start 140 | ``` 141 | ## License 142 | 143 | MIT 144 | -------------------------------------------------------------------------------- /demo/public/stages/TX Struct.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | -------------------------------------------------------------------------------- /demo/public/stages/TX Tileset Wall.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | -------------------------------------------------------------------------------- /demo/public/stages/map.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 12 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 13 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,257,269,287,270,257,257,257,257,0, 15 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,257,261,277,270,269,277,271,278,0, 16 | 284,266,267,259,275,267,266,260,268,281,284,276,258,282,275,265,281,265,274,290,305,284,267,284,281,274,257,283,284,273,284,273,282,276,268,279,270,261,264,272,270,0, 17 | 267,284,259,276,265,265,260,260,260,273,258,268,273,266,276,282,283,276,259,306,289,308,275,283,281,267,260,260,258,281,259,259,282,259,260,287,280,285,270,264,272,0, 18 | 281,267,265,276,265,273,268,258,281,282,274,275,270,266,259,273,274,274,284,290,306,292,257,282,276,260,274,282,260,281,268,274,260,268,257,258,273,276,274,270,265,0, 19 | 265,270,269,276,267,274,260,281,267,260,273,269,286,279,274,275,282,273,267,307,290,290,284,273,260,266,276,284,266,257,258,283,266,276,266,260,260,265,258,276,259,0, 20 | 265,277,271,281,260,284,277,265,283,272,287,286,270,287,279,277,265,267,259,268,305,306,281,267,257,283,266,282,268,258,284,276,267,259,284,284,258,267,265,267,282,0, 21 | 283,263,270,272,266,280,280,281,275,258,269,262,279,272,270,286,273,281,282,266,289,289,311,273,260,267,279,277,262,277,260,259,283,281,281,268,273,265,258,266,258,0, 22 | 287,271,262,277,277,264,287,273,283,260,287,262,285,277,285,264,286,259,260,273,299,305,306,258,266,283,273,287,270,280,282,276,268,273,275,265,283,258,268,283,273,0, 23 | 270,263,262,279,277,272,274,283,273,259,280,262,265,284,270,277,272,271,268,257,283,289,289,297,289,305,298,298,298,305,290,297,290,275,265,267,283,276,257,258,267,0, 24 | 286,269,264,277,280,263,275,268,260,267,281,262,285,274,260,283,262,275,281,260,268,299,290,313,301,301,304,289,290,297,305,298,305,258,266,260,279,268,281,275,267,0, 25 | 270,264,262,263,270,288,282,260,281,275,266,284,279,280,277,287,262,259,275,282,266,299,290,283,275,260,276,310,290,305,298,297,297,278,288,286,286,287,289,289,267,0, 26 | 282,271,278,262,270,288,284,268,283,267,274,259,257,284,257,265,265,265,267,284,258,305,289,265,281,258,266,281,275,310,298,289,290,264,288,285,263,278,289,289,260,0, 27 | 260,279,287,279,277,279,274,258,258,260,284,268,267,267,260,275,274,267,259,268,291,289,300,268,283,281,278,280,261,287,286,310,305,274,270,264,277,265,288,286,269,0, 28 | 282,273,286,280,259,270,274,274,282,266,268,275,282,258,257,282,265,283,259,257,291,306,308,258,259,281,271,280,278,271,261,262,257,284,266,273,276,281,264,261,278,0, 29 | 259,275,284,262,286,269,257,267,266,268,281,265,257,275,265,258,283,274,268,274,299,305,290,259,281,282,271,288,269,272,271,272,279,283,267,283,268,257,272,269,261,0, 30 | 267,276,259,273,258,284,284,281,273,275,275,268,258,283,257,275,296,258,293,297,297,297,306,283,266,283,275,286,263,287,272,287,261,269,287,257,260,278,269,287,288,0, 31 | 306,294,295,295,274,268,275,267,257,281,275,266,284,282,305,297,306,297,297,297,289,306,273,281,266,267,259,288,271,261,269,270,261,271,278,273,271,261,286,286,270,0, 32 | 298,289,297,290,298,268,275,282,267,281,276,268,259,306,298,305,305,298,298,260,275,268,282,257,268,267,283,260,282,261,288,271,288,287,277,280,271,279,287,269,280,0, 33 | 289,298,297,298,305,290,293,306,297,295,294,294,289,297,305,289,289,306,289,297,289,296,283,296,265,273,284,266,281,274,280,261,269,264,277,288,288,263,264,285,285,0, 34 | 298,297,290,298,298,290,290,306,298,289,305,289,290,290,306,306,305,289,306,301,306,298,298,290,289,294,294,267,276,274,260,276,269,264,277,271,272,263,271,278,271,0, 35 | 305,297,298,290,289,281,304,304,281,259,305,306,301,303,305,305,305,274,258,260,275,303,301,302,290,305,298,306,298,257,295,289,294,317,289,296,295,265,293,296,265,0, 36 | 298,289,298,304,273,275,273,281,282,257,283,260,274,311,268,290,289,289,310,281,281,276,257,260,260,303,303,303,305,289,289,290,298,306,290,290,297,298,290,306,305,0, 37 | 289,290,280,265,275,265,260,263,261,267,274,282,312,273,310,306,289,297,289,260,265,266,281,258,267,268,275,267,268,260,302,303,303,289,305,290,305,289,305,290,289,0, 38 | 302,267,263,262,272,266,288,280,272,260,273,283,282,282,290,311,311,298,310,265,310,260,259,267,257,281,276,260,267,258,258,260,282,275,267,306,306,306,290,290,305,0, 39 | 259,257,265,260,286,285,261,268,270,268,275,275,267,282,310,290,306,289,310,282,267,273,266,266,276,267,275,268,265,287,277,268,267,266,265,257,310,305,303,302,303,0, 40 | 258,284,284,268,278,262,277,269,263,266,283,282,267,310,276,275,297,305,309,274,276,257,273,284,281,284,283,258,276,261,269,271,271,287,269,261,286,261,287,288,260,0, 41 | 268,284,275,257,262,270,263,264,261,285,265,258,281,259,311,258,310,268,273,275,283,260,273,281,281,267,274,266,283,262,280,286,263,279,285,263,277,269,270,272,287,0, 42 | 276,273,260,276,269,277,269,272,279,280,284,258,265,266,260,284,259,275,282,266,265,257,283,284,260,259,265,283,258,257,270,280,269,285,279,279,274,287,261,264,280,0, 43 | 265,281,273,275,283,276,285,271,272,262,270,274,281,283,265,283,260,265,267,276,282,266,265,266,276,281,268,265,267,273,285,285,286,272,269,278,264,272,279,280,273,0, 44 | 266,281,283,282,273,265,260,271,271,277,261,287,286,263,284,279,278,269,271,285,285,269,270,268,285,278,269,285,272,261,286,276,288,263,269,280,264,270,279,269,285,0 45 | 46 | 47 | 48 | 49 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 50 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 51 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 52 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,374,375,376,0, 53 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,390,391,392,0, 54 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,374,375,376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 55 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,390,391,392,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 56 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,374,375,376,0,0,0,0,0,0,0,0,0,0, 57 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,390,391,392,0,0,0,0,0,0,0,0,0,0, 58 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 59 | 0,0,0,0,0,0,0,0,0,0,0,370,371,372,373,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 60 | 0,0,0,0,0,0,0,0,0,0,0,386,387,388,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 61 | 0,0,370,371,372,373,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 62 | 0,0,386,387,388,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 63 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 64 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 65 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,370,371,372,373,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 66 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,386,387,388,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 67 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 68 | 0,0,0,0,0,0,0,0,0,370,371,372,373,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 69 | 0,0,0,0,0,0,0,0,0,386,387,388,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,370,371,372,373,0,0,0,0, 70 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,386,387,388,389,0,0,0,0, 71 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 72 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 73 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 74 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 75 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 76 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,370,371,372,373,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 77 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,386,387,388,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 78 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 79 | 0,0,0,0,0,0,0,0,370,371,372,373,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 80 | 0,0,0,0,0,0,0,0,386,387,388,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 81 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 82 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 83 | 84 | 85 | 86 | 87 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 88 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 89 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 90 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1180,0,0,1180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 91 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1196,0,0,1196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 92 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1212,0,0,1212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 93 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 94 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1278,1279,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 95 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1294,1295,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 96 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 97 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1214,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 98 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 99 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 100 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 101 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 102 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 103 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 104 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 105 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1102,1103,1104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 106 | 0,0,0,0,0,1180,0,0,0,0,0,0,1098,1099,1118,1119,1120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 107 | 0,0,0,0,0,1196,0,0,0,0,0,0,1114,1115,1134,1135,1136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 108 | 0,0,0,0,0,1212,0,0,0,0,0,0,0,0,1228,1229,1230,0,0,0,0,0,0,0,0,0,0,0,1278,1279,0,0,0,0,0,0,0,0,0,0,0,0, 109 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1244,1245,1246,0,0,0,0,0,0,0,0,0,0,0,1294,1295,0,0,0,0,0,0,0,0,0,0,1180,0, 110 | 0,0,0,0,0,1180,0,0,0,0,0,0,0,0,1260,1261,1262,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1196,0, 111 | 0,0,0,0,0,1196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1212,0, 112 | 0,0,0,0,0,1212,0,0,0,0,0,0,1149,0,0,0,0,0,0,0,1117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 113 | 0,0,0,0,0,0,0,0,0,0,0,0,1165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1180,0, 114 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1196,0, 115 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1212,0, 116 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 117 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1240,0,1240,0,1240,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 118 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1256,0,1256,0,1256,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 119 | 1279,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1208,0,1240,0,1208,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 120 | 1295,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1224,0,1256,0,1224,0,1210,0,0,0,0,0,0,0,0,0,0,0,0 121 | 122 | 123 | 124 | 125 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 126 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 127 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 129 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 130 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 131 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 132 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 133 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 134 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 135 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 136 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 137 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 138 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 139 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 140 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 141 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 142 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 143 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 144 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 145 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 146 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 147 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 148 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 149 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 150 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 151 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 152 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 153 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 154 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 155 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 156 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 157 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 158 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 159 | 160 | 161 | 162 | 163 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 164 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 165 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 166 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,594,595,595,595,595,595,595,596,0, 167 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,610,0,0,0,0,0,0,612,0, 168 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,594,595,595,595,595,595,595,595,595,595,610,0,0,0,0,0,0,612,0, 169 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,610,0,0,0,0,0,0,0,0,0,610,0,0,0,0,0,0,612,0, 170 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,610,0,0,0,0,0,0,0,0,0,626,674,676,677,601,0,0,612,0, 171 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,610,0,0,0,0,0,0,0,0,0,642,691,692,691,610,0,0,612,0, 172 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,610,0,0,0,0,0,0,0,0,0,0,0,0,0,626,853,854,628,0, 173 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,626,677,676,677,679,675,675,850,851,0,0,0,0,0,642,869,870,644,0, 174 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,642,692,690,691,695,692,693,866,867,610,0,0,0,0,0,885,886,612,0, 175 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,882,883,626,601,0,0,0,0,0,0,612,0, 176 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,642,610,0,0,0,0,0,0,612,0, 177 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,610,0,0,0,597,910,911,628,0, 178 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,610,0,0,0,612,926,927,644,0, 179 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,610,0,0,0,612,0,0,0,0, 180 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,626,676,677,675,628,0,0,0,0, 181 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,642,690,693,690,644,0,0,0,0, 182 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 183 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 184 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 185 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 186 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 187 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 188 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 189 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 190 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 191 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 192 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 193 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 194 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 195 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 196 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 197 | 198 | 199 | 200 | 201 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,8,9, 202 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,23,24,25, 203 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,39,40,41, 204 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,23,24,0,0,0,0,0,0,0,0,0,0,0,0,54,55,56,57, 205 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,39,40,0,0,0,6,7,8,0,0,0,0,0,0,70,71,72,73, 206 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,54,55,56,0,0,0,22,23,24,0,0,0,0,0,0,0,0,0,0, 207 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,71,72,0,0,0,38,39,40,0,0,0,0,0,0,0,0,0,0, 208 | 0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,54,55,56,0,0,0,0,0,0,0,0,0,0, 209 | 0,0,0,0,0,0,0,0,0,0,17,18,19,20,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,71,72,0,0,0,0,0,0,0,0,0,0, 210 | 0,1,2,3,4,5,0,0,0,0,33,34,35,36,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 211 | 0,17,18,19,20,21,0,0,0,0,49,50,51,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 212 | 0,33,34,35,36,37,0,0,0,0,65,66,67,68,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 213 | 0,49,50,51,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 214 | 0,65,66,67,68,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 215 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,18,19,20,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 216 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,34,35,36,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 217 | 0,0,0,0,0,0,0,0,1,2,3,4,5,0,0,0,0,0,0,0,0,0,49,50,51,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 218 | 0,0,0,0,0,0,0,0,17,18,19,20,21,0,0,0,0,0,0,0,0,0,65,66,67,68,69,0,0,0,0,0,0,1,2,3,4,5,0,0,0,0, 219 | 0,0,0,0,0,0,0,0,33,34,35,36,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,98,0,0,0,17,18,19,20,21,0,0,0,0, 220 | 0,0,0,0,0,0,0,0,49,50,51,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,98,0,0,33,34,35,36,37,0,0,0,0, 221 | 0,0,0,0,0,0,0,0,65,66,67,68,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,50,51,52,53,98,0,0,0, 222 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,65,66,67,98,69,0,0,0,0, 223 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,0,98,0,0,0, 224 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,98,0,0,0,0,0,0, 225 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 226 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,18,19,20,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 227 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,34,35,36,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 228 | 0,0,98,0,0,0,98,1,2,3,4,5,0,0,0,0,0,0,0,0,0,0,49,50,51,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 229 | 0,0,0,0,0,98,0,17,18,19,20,21,0,0,0,0,0,0,0,0,0,0,65,66,67,68,69,0,0,0,0,0,98,0,0,0,0,0,0,0,0,0, 230 | 98,98,0,0,0,0,0,33,34,35,36,37,0,0,0,0,0,0,0,0,0,98,0,0,0,0,0,0,0,0,0,0,98,98,98,98,0,0,0,0,0,0, 231 | 0,0,0,98,0,0,0,98,50,51,52,53,0,0,0,0,0,0,0,0,0,98,0,0,0,0,0,0,0,0,98,0,0,0,0,98,98,0,0,0,0,0, 232 | 0,0,98,0,98,0,98,98,66,67,68,69,0,98,0,98,98,0,0,0,0,0,0,0,0,0,0,0,0,98,98,0,0,0,0,98,98,0,0,0,0,0, 233 | 0,0,0,98,0,98,0,0,0,0,0,0,0,0,0,0,98,98,98,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,98,98,98,98,98,98,0, 234 | 0,0,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,0,98,98,0,0,0,0 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | --------------------------------------------------------------------------------