24
\$\begingroup\$

Part 2 of the challenge is here

Flags Mashup Bot is a small Twitter bot that generates a new flag based on two random flags and tweets the result every couple of minutes.

Task

Your task is to replicate what the bot does by writing a script or a function based on the following criteria:

  • The input is any two lossless images composed of at least two, but no more than eight colours.
  • To mix up the flags the following algorithm has to be used:
    • Take the first image
    • For every colour in the first image assign a colour randomly from the second image
    • Each colour from the second image has to be used at least once
      • Unless there are less colours in the first image than colours in the second.
      • You can choose randomly which colours to drop from the second image in this case.
    • Each colour from the first image has to be replaced with a different colour
      • Unless there are not enough colours in the second image.
      • You can choose randomly which colours will be used multiple times in this case.
      • However you need to make sure none of the colours are used more than any other colour by more than one
      • example: if you need to assign 2 colours to a flag of 5 colours you'll need to use one of the colour 3 times, while the other one 2 times. You cannot mix them 1 & 4
    • If a colour is present in both images you cannot assign that colour with itself you'll need to pick another one
  • The output is the resulting image

Examples

UK & Hungary

Example 1

Notes: Both flags have three colours, however both use red and white, so those have to be replaced, hence the first invalid example. The second one doesn't use all three colours, and the third one uses non-existent colours.

South Africa & Sweden

Example 2

Notes: South Africa's flag has 6 colours, while Sweden's have 2, meaning each of the two colours have to be used exactly 3 times. The invalid ones use the colours in a way which is not compatible with this constraint. Note that although both flags use the colour yellow they are actually not the same shade so are considered different

Poland & Poland

Example 3

Notes: The only valid solution is switching up the two colours.

Notes

  • The two images don't need to have the same dimensions
  • The colour list can be different for the two images, so in total there might be 16 colours
  • The input can be either a lossless image file (example GIF, PNG, BMP, SVG, etc.), or (especially in case of functions) a two dimensional bitmap array holding the colours of the image in any reasonable format. Any native way of storing a bitmap in your language is also fine.
  • For both input and output images a two dimensional array holding ASCII characters, where different characters count as different colours, counts as a reasonable format, but solutions that work on "real" bitmaps are preferred
  • The output and input formats don't need to match
  • I think the colour replacement rules won't prohibit it to work for any valid two input images, but if yes your program doesn't need to work for them
  • Colours are considered the same only if they are exactly the same based on their RGB value. E.g. #FF0000 and #FF0001 are considered two different colours.
  • Standard loopholes, as usual, are prohibited

, so shortest code by byte count wins and will be accepted. If possible please include example a set of input & output images with your submission

\$\endgroup\$
  • \$\begingroup\$ UK+Hungary= Basque country \$\endgroup\$ – Brain Guider Nov 20 at 21:51
4
\$\begingroup\$

Jelly, 40 25 bytes

FQ),ṁ@¥/Ẋ€⁺ZE€ẸƊ¿iⱮⱮ@ịƭƒḢ

Try it online!

A monadic link taking a list of two flags as integer matrices and returning the altered version of the first flag. At the moment this assumes there are indexed colours representing each pixel. I've also assumed that each flag can have arbitrary colours.

\$\endgroup\$
16
\$\begingroup\$

Mathematica, 116 chars, 118 bytes

Mathematica's ColorReplacep[] function paired with DominantColors[] is really good at this sort of problem.

n=DominantColors;ColorReplace[#1,#1->#2&@@@({##})&[n@#1,Flatten[RandomSample@Permutations@n@#2][[;;Length@n@#1]]]]&

Also, mathematica has built in bitmaps for all countries if you install the countrydata package. One can demonstrate the above code with the following function call:

%[CountryData["UnitedStates", "Flag"], CountryData["Hungary", "Flag"]]

This randomly generates something like:

shuffled flag

The output is random, but we can repeat the test as many times as we want to show there is no repetition of colors (unless the bitmap #2 has less colors than we need):

shuffled flags

\$\endgroup\$
  • 2
    \$\begingroup\$ In your example the white in the US flag remained white after the colour change which is not allowed, e.g. If a colour is present in both images you cannot assign that colour with itself you'll need to pick another one \$\endgroup\$ – SztupY Nov 20 at 12:43
  • 1
    \$\begingroup\$ You're correct, I now realize I misunderstood the question. I will amend my solution as soon as I have time. \$\endgroup\$ – ralian Nov 20 at 17:43
  • \$\begingroup\$ @ralian You can temporarily delete your answer whilst fixing it. This is preferred, since challenges should only have answers that correctly solve them. \$\endgroup\$ – Jonathan Frech Nov 26 at 21:45
11
\$\begingroup\$

JavaScript (Node.js),  160  159 bytes

I/O format: matrix of 24-bit integers.

Takes input as (a)(b).

a=>F=b=>(g=a=>[...new Set(a.flat())].sort(_=>Math.random()-.5))(a).every((c,i)=>c^=F[c]=B[i%B.length],B=g(b).slice(-g(a).length))?a.map(r=>r.map(c=>F[c])):F(b)

Try it online!

Commented

Helper function

The helper function \$g\$ takes a matrix as input and returns a shuffled list of the distinct values it holds.

g = a =>
  [...new Set(a.flat())]
  .sort(_ => Math.random() - .5)

Main code

a => F = b =>                 // a[] = first image, b[] = second image
  g(a).every((c, i) =>        // for each color c at position i in the list of shuffled
                              // colors of the first image:
    c ^=                      //   make sure that c is different from the
      F[c] = B[i % B.length], //     substitute color F[c] picked from the second image
    B =                       //   define B[] as:
      g(b)                    //     the list of shuffled colors from the second image
      .slice(-g(a).length)    //     resized to the number of colors in the first image
  ) ?                         // end of every(); if truthy:
    a.map(r =>                //   return a[] with each original color
      r.map(c => F[c])        //   replaced with its substitute color
    )                         //
  :                           // else:
    F(b)                      //   try again
\$\endgroup\$
5
\$\begingroup\$

Python 2, 196 bytes

Takes input as two lists of lists, where different elements represent different colors. Anything can be used to represent color: number, hex, string, etc.

from random import*
P=input()
i,j=(list(set(sum(x,[])))for x in P)
d={0:0}
while any(i==d[i]for i in d):y=[];exec'y+=sample(j,len(j));'*len(i);d=dict(zip(i,y))
print[[d[c]for c in r]for r in P[0]]

Try it online!


Explanation:

# get unique elements from input
P=input()
i,j=(list(set(sum(x,[])))for x in P)  
# create dictionary, where colors of first image are keys and colors of second image are values
d={0:0}
# keep creating while no color is paired with same color
while any(i==d[i]for i in d):
  y=[]
  # sum different samples of substitution colors to keep random
  # and to make sure none of the colors are used more than any other color by more than one
  # *len(i) is to ensure that we have enough values to match
  exec'y+=sample(j,len(j));'*len(i)
  d=dict(zip(i,y))
# substitute colors and output result
print[[d[c]for c in r]for r in P[0]]
\$\endgroup\$
3
\$\begingroup\$

Perl 5, 170 168 bytes

sub f{($a,$b,$e)=map[uniq(/./g)],@_;%n=map{($_,0)}@$b;%s=map{$c=$$b[rand@$b];$e+=/$c/;$n{$c}++;($_,$c)}@$a;@v=values%n;max(@v)-min(@v)>1||$e?f(@_):$_[0]=~s,.,$s{$&},gr}

Try it online!

With spaces, newlines, my's, comments and a small test script added:

sub f{
  my($a,$b,$e)=map[uniq(/./g)],@_; #$a and $b are now arrayrefs to the unique
                                   #  colors in each flag
  my %n=map{($_,0)}@$b;          #init %n with 0 values for each col in flag2
  my %s=map{                     #%s becomes a suggested swap hash
    $c=$$b[rand@$b];             #draw random color from flag2
    $e += /$c/;                  #short for: $error=true if $_ eq $c
    $n{$c}++;                    #count usages of each flag2 color
    ($_,$c)                      #suggest swap this col in flag1 with random
                                 #  col in flag2
  }
  @$a;
  my @v=values%n;
  max(@v)-min(@v)>1              #no more than one more usages of each flag2 color
  || $e                          #cannot swap with itself
  ?  f(@_)                       #retry if %s don't passes
  :  $_[0]=~s,.,$s{$&},gr        #swap colors with %s if %s passes the demands
}

srand(1);
for(1..20){
    my($flag1,$flag2)=
      grep{/../&&!/(.).*\1/||redo}
      map{join'',map chr(65+rand(16)),0..rand(8)}
      1..2;
    ($flag1,$flag2)=qw(GWRYBb Ey) if $_==18; #south africa & sweden example                                                                                                                             
    ($flag1,$flag2)=qw(RWB RWG)   if $_==19; #uk & hungary example                                                                                                                                      
    ($flag1,$flag2)=qw(WR WR)     if $_==20; #poland example                                                                                                                                            
    my @s=uniq(map f($flag1,$flag2),1..1000);
    print "flag1=$flag1 flag2=$flag2 @{[0+@s]} solutions: ".join(" ",@s)."\n";
}
use List::Util qw(uniq min max);

The image format consists of up to sixteen different capital letters A-P for each pixel. The letter represents a color in a color map (like in gifs). Max eight unique colors in each flag. The function returns the first argument ($a) where each letter is (potentially) swapped with a letter in the second argument ($b) through the swap hash %s. The %n hash is used to count the number of colers each swapped in color is used for and the least frequent (can be zero) shouldn't be less than one below the max frequency. Also $e (error) becomes true if f attempts to swap a color with itself in which case f is also run again.

\$\endgroup\$
1
\$\begingroup\$

Charcoal, 70 bytes

WS⟦ι⟧WΦKA¬№υκ⊞υ‽ι≔υθ≔⟦⟧ηWSFιF¬№ηκ⊞ηκW⊙υ⁼κ§θλ«≔⟦⟧θWΦη¬№θλ⊞θ‽κ»UMKA§θ⌕υι

Try it online! Link is to verbose version of code. Takes input as character arrays, where different characters represent different colours. For the link I've rendered two flags in ASCII art. Explanation:

WS⟦ι⟧

Input and print the first character array.

WΦKA¬№υκ⊞υ‽ι

Randomly extract the distinct characters into a list.

≔υθ

Make a temporary copy of the list. This copy will be replaced by a shuffle of the transliteration characters.

≔⟦⟧η

Create a second list. (The first list was automatically predefined by Charcoal.)

WSFιF¬№ηκ⊞ηκ

Input the second character array and extract the unique characters to the second list.

W⊙υ⁼κ§θλ«

Repeat while at least one character in the first list maps to a character in the second list. The mapping is cyclic, so that once all of the colours run out, they are reused again in the same order, thus ensuring that no colour is used an unbalanced number of times.

≔⟦⟧θWΦη¬№θλ⊞θ‽κ

Shuffle the unique characters from the second list.

»UMKA§θ⌕υι

Once a distinct shuffle has been found, transliterate the whole canvas from the first to the second list.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.