Make America(n Maps) Great Again

16

5

New Bonus! (See below)

The cartography team of U.S. Republican presidential hopeful Ben Carson is having some trouble with their maps (image via Washington Post):

Map with a bunch of states moved to the wrong places (by Ben Carson's campaign team) and a real map of the US next to it

The problem is they don't have the Right Tool For The Job™. They need the most compact and reliable program possible, so they never have to worry about making maps again. That's why they hired you. You need to take this map and output it again with the desired coloring:

Blank map of the United States with state borders shown

By Theshibboleth [GFDL (http://www.gnu.org/copyleft/fdl.html) or CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0/)], via Wikimedia Commons

If you don't know where all the states are (because you are not an American...or you are an American), here is a map with all the names (Washington D.C. is not required for this challenge): Map of the United States with state borders and names on it

"Map of USA with state names 2". Licensed under CC BY-SA 3.0 via Wikimedia Commons - https://commons.wikimedia.org/wiki/File:Map_of_USA_with_state_names_2.svg#/media/File:Map_of_USA_with_state_names_2.svg

For example if the input is Ohio, Indiana, Illinois;New York, New Jersey, Florida, you output: Map of the United states with state borders. Ohio, Indiana and Illinois are colored in red; New York, New Jersey Florida are colored in blue.

The blank map image is available in SVG and PNG formats. For your convenience, here is a list of all 50 states in alphabetical order

This is a and challenge. Output must be as a SVG or image file. Simply displaying the output on the screen is not enough. Input must be taken from STDIN or by reading a text file. I am flexible with how you format the input, although it should contain the full names of each state, with red (Republican) states listed first and blue (Democratic) states second. Any two distinct shades of red and blue are acceptable for the coloring. Of course, you can have the blank map image in the same folder as your program with whatever file name you want.

Accuracy Criteria

If your output is a raster file, it must be at least 800px by 495px, and the lines should not deviate from the result of scaling up the SVG to the same size by more than 1.5 pixels. If your output is a vector file, the lines should not deviate from the SVG by more than 1.5 pixels when both are scaled to 800px by 495px.

Bonus!

Ben is trying to cut down dependence on foreign libraries, and is now offering a -50% bonus to anyone who uses only a raster graphics version of the map as input and creates their own algorithm for region detection. Ultimately, it is my judgment that determines whether your approach counts as "writing your own" algorithm.

Good Luck!

geokavel

Posted 2015-11-19T16:59:31.243

Reputation: 6 352

the example shows some aliasing around the lines that hasn't been filled in. is that acceptable? – Sparr – 2015-11-19T17:25:49.897

@Sparr I made the example with an image editor, so I consider it to be "perfect", so if you miss anything that it misses it's alright. – geokavel – 2015-11-19T17:49:11.103

Just to be sure: are we allowed to modified the blank SVG file? Does its size count in our score? What do you mean by "simply displaying the output on the screen is not enough"? – Blackhole – 2015-11-19T20:55:06.373

@Blackhole No, you can't modify the blank SVG file, but it doesn't count as part of your score as long as you load it externally. – geokavel – 2015-11-19T21:32:25.053

@Blackhole What I mean is, you have to output a file. – geokavel – 2015-11-19T21:32:56.443

When you say "I am flexible with how you format the input", does that mean that a really strange formatting like Ohio0Indiana0Illinois1New York0New Jersey0Florida is allowed? – Blackhole – 2015-11-19T22:16:17.013

@Blackhole Yeah, I am ok with that. – geokavel – 2015-11-19T22:22:02.680

how flexible? can my input just be a list of 50 ternary digits, in a specific order (alphabetical states, perhaps)? – Sparr – 2015-11-21T18:38:26.360

@Sparr "I am flexible with how you format the input, although it should contain the full names of each state." It has to be human-readable names of each state, and it has to work even if they're not in alphabetical order. – geokavel – 2015-11-21T18:42:42.200

For the record, a semi-related xkcd exists.

– Joe – 2016-09-04T02:46:48.150

Answers

7

Python 626

In the approach below, I added .rstate and .bstate based on .state in the CSS description. In my I renamed the provided .svg file to v.svg. It takes an input as described below and writes to a file w.png. To transfer from the full state name to the abbreviated version I look them up based on the first and last two letters of the states.

r='Ama,Aka,Ana,Aas,Cia,Cdo,Cut,Dre,Fda,Gia,Hii,Iho,Iis,Ina,Iwa,Kas,Kky,Lna,Mne,Mnd,Mts,Man,Mta,Mpi,Mri,Mna,Nka,Nda,Nre,Ney,Nco,Nrk,Nna,Nta,Oio,Oma,Oon,Pia,Rnd,Sna,Sta,Tee,Tas,Uah,Vnt,Via,Won,Wia,Win,Wng'.split(',')
y='lkzraotelaidlnasyaedainsotevhjmycdhkraicdnxttaaviy'
v=open('v.svg','r')
s=v.read()
v.close()
k=s.find('.state')
j=s.find('.',k+1)
t=input().split(';')
w=open('w.svg','w')
k+=1
c='#E0E0E0'
s=s[:j]+'.r'+s[k:j].replace(c,'red')+'.b'+s[k:j].replace(c,'blue')+s[j:]
c='rb'
for j in range(2):
 for d in t[j].split(','):k=s.find('state '+d[0].lower()+y[r.index(d[0]+d[-2:])]);s=s[:k]+c[j]+s[k:]
w.write(s)
w.close()

Example input:

'California,Illinois,Iowa,Mississippi;New Mexico,Pennsylvania,South Dakota,Vermont'

Example output: output figure

Or inspired by the flag of France: output figure france

Willem

Posted 2015-11-19T16:59:31.243

Reputation: 1 528

Nice one, democracy lives on! – geokavel – 2015-11-22T01:40:47.660

Congratulations, you are the winner! Thanks to everyone who participated! – geokavel – 2015-11-27T02:33:16.490

6

Processing, 425 bytes (259 bytes + 1 +165 byte file)

Code:

size(959,593);String[]a=loadStrings("a"),b=loadStrings("b");PShape m=loadShape("M.svg");m.disableStyle();for(int i=0;i<51;i++){fill(255);int r=0;for(String j:a){if(j.isEmpty())r++;if(j.contains(b[i]))fill(r>0?#0000FF:#FF0000);}shape(m.getChild(i));}save("m");

Blank map should be named "M.svg" and stored in a folder called /data (all other files are in the same folder as the program.)

Input File ("a"):

Mississippi
California
Connecticut

Delaware
Florida
Wyoming
Hawaii

Key File ("b"): http://pastebin.com/0pNufAH9

Output ("m.tif"):

enter image description here

Ok, here is my try at my own challenge. Some notes:

  • The output map looks different from the input map in the following ways
    1. The input map had grey filling on a transparent background. The output has white filling on a gray background. I think this should be allowed, because white, gray, and transparency are all neutral.
    2. The output map is missing the lines around Hawaii and Alaska that the input had. Once again, I think this is ok because the lines are not a significant part of the map.
  • The program uses an external file to hold keys. According to this meta post, I just need to add 1 byte for one additional file.

If anyone has any discrepancies with my self-adjudication of my code, feel free to leave a comment.

Also, if anyone is curious about trying this challenge in Processing, it supports both reading SVG files into PShape's, as well as parsing SVG files as XML.

geokavel

Posted 2015-11-19T16:59:31.243

Reputation: 6 352

For your for-loop, have for(int i=0;i++<51;) instead of for(int i=0;i<51;i++). It saves 1 byte and it has a smiley face in it ;) – user41805 – 2015-11-21T12:44:36.693

@ΚριτικσιΛίθος I had to make it ++i for it to work. Does that sound right? – geokavel – 2015-11-21T18:36:12.537

@ΚριτικσιΛίθος It might save a byte, but it completely changes the behaviour inside the loop. – Tom Carpenter – 2015-11-21T18:49:20.920

@ΚριτικσιΛίθος Yeah, I guess I can't use that then because I lose Hawaii. Maybe it works different in Java then other languages. – geokavel – 2015-11-21T18:59:30.467

You have got an extra useless space at String[] a – user41805 – 2015-11-21T19:54:38.420

@ΚριτικσιΛίθος Nice tip, thanks! – geokavel – 2015-11-21T20:39:51.850

5

PHP, 714 bytes

The output is the blank SVG file, which should be stored in a file named a, with additional CSS to colour the states, which should be stored in a file named b in the following format:

Ohio0Indiana0Illinois1New York0New Jersey0Florida

I've added some newlines for readability.

<?
$x=str_replace;echo$x('.b','#'.$x([0,1],[',#','{fill:red}#'],$x(split(0,'Alabama0Alaska0
Arizona0Arkansas0California0Colorado0Connecticut0Delaware0Florida0Georgia0Hawaii0Idaho0Illin
ois0Indiana0Iowa0Kansas0Kentucky0Louisiana0Maine0Maryland0Massachusetts0Michigan0Minnesota0M
ississippi0Missouri0Montana0Nebraska0Nevada0New Hampshire0New Jersey0New Mexico0New York0Nor
th Carolina0North Dakota0Ohio0Oklahoma0Oregon0Pennsylvania0Rhode Island0South Carolina0South
 Dakota0Tennessee0Texas0Utah0Vermont0Virginia0Washington0West Virginia0Wisconsin0Wyoming'),s
tr_split(ALAKAZARCACOCTDEFLGAHIIDILINIAKSKYLAMEMDMAMIMNMSMOMTNENVNHNJNMNYNCNDOHOKORPARISCSDT
NTXUTVTVAWAWVWIWY,2),file(b)[0])).'{fill:blue}.b',implode('',file(a)));

Here is the ungolfed version:

<?php
$stateNames = 'Alabama0Alaska0Arizona0Arkansas0California0Colorado0Connecticut0Delaware0Florida0Georgia0Hawaii0Idaho0Illinois0Indiana0Iowa0Kansas0Kentucky0Louisiana0Maine0Maryland0Massachusetts0Michigan0Minnesota0Mississippi0Missouri0Montana0Nebraska0Nevada0New Hampshire0New Jersey0New Mexico0New York0North Carolina0North Dakota0Ohio0Oklahoma0Oregon0Pennsylvania0Rhode Island0South Carolina0South Dakota0Tennessee0Texas0Utah0Vermont0Virginia0Washington0West Virginia0Wisconsin0Wyoming';
$statesAbbreviations = 'ALAKAZARCACOCTDEFLGAHIIDILINIAKSKYLAMEMDMAMIMNMSMOMTNENVNHNJNMNYNCNDOHOKORPARISCSDTNTXUTVTVAWAWVWIWY';

$blankSVG = implode('', file('a'));

$inputWithStateNames = file('b')[0];
$inputWithStateAbbreviations = str_replace(
    explode('0', $stateNames),
    str_split($statesAbbreviations, 2),
    $inputWithStateNames
);

echo str_replace(
    '.border',
    '#'. str_replace(
        [
            '0',
            '1'
        ],
        [
            ',#',
            '{fill:red}#'
        ],
        $inputWithStateAbbreviations
    ) .'{fill:blue}.border',
    $blankSVG
);

The principle is simple: in the blank SVG, each path has an ID corresponding to the abbreviation of the state that it represents (for instance, <path d="…" id="HI" /> for Hawaii).

All we have to do is to add some CSS to colour this path in the appropriate shade. But there is already some CSS in the blank file (in particular the <style type="text/css">…</style> tag already exists), so it's really easy and short to do it. We can notice than the string .b is only found in the CSS for .border. Good news! We'll just replace .b with OUR_WONDERFUL_CSS.b.

Creating "our wonderful CSS" is not really more difficult:

  1. Read the input from the file:
    Ohio0Indiana0Illinois1New York0New Jersey0Florida.
  2. Replace the names of the states with their abbreviations:
    OH0IN0IL1NY0NJ0FL.
  3. Replace the 0 characters with ,#:
    OH,#IN,#IL1NY,#NJ,#FL.
  4. Replace the 1 character with {fill:red}#:
    OH,#IN,#IL{fill:red}#NY,#NJ,#FL.
  5. Add # at the beginning and {fill:blue} at the end:
    #OH,#IN,#IL{fill:red}#NY,#NJ,#FL{fill:blue}.

Blackhole

Posted 2015-11-19T16:59:31.243

Reputation: 2 362

Ok, great job. While technically it doesn't write a file as I would want, the user can easily save image by pushing "Save Page As" in the browser. I'll allow this type of answer. – geokavel – 2015-11-19T23:46:34.677

3Interesting that the abbreviations for Pennsylvania, Rhode Island, and South Carolina spell out PARIS. – geokavel – 2015-11-19T23:58:22.787

@geokavel I can easily create a file, if necessary. Should I modify my answer? Yep, long live Paris! By the way, thanks for your support in this tough times, brothers beyond the Atlantic! – Blackhole – 2015-11-20T21:09:59.773

@DavidCarraher I've added some explanations. I hope it will help you to understand my answer. – Blackhole – 2015-11-20T21:10:28.887

+1 for implode and your username! – caird coinheringaahing – 2017-05-21T12:38:15.743

3

Mathematica 1025

Not elegant but it works.

I wasn't aware that SVG files had paths for each state, so I found the states using MorphologicalComponents and then associated each component with its respective state. States like Michigan (with upper and lower peninsulas) and Hawaii (multiple islands) have more than one component.

The code assumes that the map file is contained in the variable, m.

r=Thread[{"Washington","Montana","Maine","Minnesota","North Dakota","Oregon","Michigan","New Hampshire","Vermont","Wisconsin","New York","Idaho","South Dakota","Wyoming","Massachusetts","California","Connecticut","Nevada","Pennsylvania","Iowa","New Mexico","New Jersey","Ohio","Nebraska","Illinois","Indiana","Colorado","Delaware","Maryland","West Virginia","Virginia","Missouri","Washington, D.C.","Kansas","Kentucky","North Carolina","New Mexico","Tennessee","Arizona","Oklahoma","Arkansas","South Carolina","Georgia","Alabama","Mississippi","Texas","Louisiana","Alaska","Florida","Hawaii"}->{6,7,8,9,10,11,{13,23},14,16,18,{19,39},20,24,25,26,27,31,32,36,37,38,40,41,42,43,44,45,46,{47,55},49,50,51,52,53,56,57,58,59,60,61,62,65,66,67,69,{71,80,87},72,{73,75,82,93,101,104},74,{79,81,83,84,85,89,92}}]; 
v=Flatten;c=MorphologicalComponents@Binarize@m;
h@s_:=v[((Reverse/@Position[c,#])/.{x_,y_}:>{x,1241-y})&/@s,1]
k@{s_,c_}:=Thread[(h@s)->c]
f@{a_,b_}:=Export["f.jpg",(ReplacePixelValue[map,v[k[{v[#/.r],#2}]&@@@{{a,Red},{b,Blue}}]])]

Below is the image that will be exported by the following input:

f[{{"Ohio", "Indiana", "Illinois", "Alaska"}, {"New York", "Michigan","Oregon", "New Jersey", "Florida"}}]

map

DavidC

Posted 2015-11-19T16:59:31.243

Reputation: 24 524