Паззл из стран Mercator. Подготовка данных (ruby)
Jul 18, 2013 21:28 · 394 words · 2 minute read
Содержание:
Итак, у нас есть XML файл с координатами стран, теперь хорошо бы его загнать в базу данных. В нашем случае это PostgreSQL. Делать мы это будем с помощью замечательного языка Ruby. Для этого установим gem для работы с Postgres по имени pg (неожиданно, правда?):
$ gem install pg
Но для начала создадим структуру БД:
-- создадим пользователя mercator
CREATE ROLE mercator LOGIN NOSUPERUSER INHERIT CREATEDB NOCREATEROLE NOREPLICATION;
-- добавим ему схему
CREATE SCHEMA mercator AUTHORIZATION mercator;
-- последовательность для таблицы стран
CREATE SEQUENCE countries_seq INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807
START 1 CACHE 1;
ALTER TABLE countries_seq OWNER TO mercator;
-- создадим таблицу стран
CREATE TABLE "Countries"(
"ID" integer NOT NULL DEFAULT nextval('countries_seq'::regclass),
"Name" character varying(50) NOT NULL, -- имя страны
"Level" character varying, -- кажется, масштаб, но пока не используется
"Polygon" character varying[], -- список полигонов в виде строк
"Available" boolean, -- доступность для игры
"Answer" character varying(50), -- хранение ответа
CONSTRAINT "CountriesID" PRIMARY KEY ("ID" )
) WITH (OIDS=FALSE);
ALTER TABLE "Countries" OWNER TO mercator;
Теперь можно попробовать подключиться через пользователя mercator/mercator:
require 'pg'
$connection = PG::Connection.new( :host => '127.0.0.1', :port => 5432,
:dbname => 'mercator', :user => 'mercator', :password => 'mercator')
$connection.prepare('stm', 'INSERT INTO "Countries"("Name", "Polygon", "Answer") values ($1, ARRAY[$2], $3)')
Знак доллара в имени переменной означает, что она глобальна. Осталось распарсить KML-файл, преобразовать полигоны из массива в строку (для каждой страны!), сгенерировать ответ и поместить всё это добро в таблицу:
require 'rexml/document'
xmldoc = Document.new(File.new("countries_world.xml"))
xmldoc.elements.each("kml/Document/Placemark"){
|e|
name = e.elements["name"].text
puts "Processing " + name
gmapPolygon = getPolygons(e)
answer = getAnswer(e)
$connection.exec_prepared('stm', [name, gmapPolygon, answer])
}
Целиком код можно посмотреть на github. Уточню разве что небольшие детали:
- конвертация из массива координат в строку для GoogleMapsAPI делал этой утилитой, причём там важно следить что идёт первым в кортеже - широта или долгота;
- ответ представляет собой 4 координаты (прямоугольник), в который помещается страна. Для упрощения задачи игроку я прибавил с каждой стороны по одному градусу (долготы или широты). В связи с этим, кстати, возникла проблема с Канадой и Россией - у них северные координаты располагаются уж больно близко к полюсу и попасть в такой прямоугольник становится невозможно.
Теперь у нас есть страны в базе данных. В следующей статье посмотрим как их можно доставать с помощью erlang, генерировать js и отдавать клиенту.
UPD
Проект переписан на другие технологии, улучшен и запущен на сайте https://geopuzzle.org.