Background and Motivation:

IOC Country Codes are three letter abbreviations that are commonly used when broadcasting the Olympic Games. The last two letters of some codes overlap with the first two letters of other codes (RUS -> USA, JPN -> PNG), etc. Clearly, you can transform the first country code into the second by removing the first letter, and adding a new letter at the end. Sometimes, you can chain these transformations into a longer path (RUS -> USA -> SAM).

I want to find determine whether a path exists between 2 given country codes (using a provided list like the IOC list or the FIFA list) in order to impress party guests, and in the event that multiple paths exist, I'd like to output the longest one. To keep the output small enough to sneak into a commercial break, paths are compressed by not repeating common substrings between adjacent country codes: RUS -> USA -> SAM would be written as RUSAMfor example.

If multiple equal length paths are possible, you can select any result (previously asked for a deterministic tiebreaking rule that "I could explain to a partygoer." I would still appreciate answers that include this, but it's probably not a good objective rule that constrains whether an answer is correct.)

The Technical Challenge


  • initial 3 letter country code
  • terminal 3 letter country code
  • set of valid 3 letter country codes


Determine whether a string exists such that:

  • the first three letters are identical to the initial 3 letter country code
  • The last three letters are identical to the terminal 3 letter country code
  • each 3-letter substring corresponds to a valid country code from the input set
  • the same country code cannot appear twice in the string (with the exception that the first 3 characters and the last 3 characters can be the same)

If one such string exists, print that string as the output. If multiple such strings exist, print the longest such string. If no such string exists, any of the following are acceptable:

  • no output
  • falsey output
  • error

Other ways of indicating that no such path exists are also allowed as long as they can't be confused for a valid path.

Valid Assumptions:

*The initial 3 letter country code and the terminal 3 letter country code are both contained in the provided set of valid 3 letter country codes.

Invalid Assumptions:

*The input set cannot be assumed to be ordered for purposes of producing a deterministic output.

*The initial 3 letter country code cannot be assumed to be different from the terminal country code (cyclic requests are allowed)

Extra Style Points (Not Necessary for Submission to be Valid):

If your answer includes a description of a deterministic tie-breaking rule you are using to determine which string to output when multiple identical length strings exist that meet all the above criteria, then you'll make this internet stranger very happy. Preferably something easy enough to explain to a random Olympics viewer, which is too fuzzy to be a good requirement for a valid submission.


This is code golf, so the shortest answer (in bytes) wins. Standard Loopholes apply.

Test Cases

Input 1: "AAA", "ZZZ", ["AAA", "AAZ", "AZZ", "ZZZ"]

Output 1: "AAAZZZ" (Find valid path if it exists)

Input 2: "AAA", "ZZZ", ["AAA", "AAZ", "AZZ", "ZZZ", "AAB", "ABB", "BBB", "BBZ", "BZZ", "ZZZ"]

Output 2: "AAABBBZZZ" (Find longest path if short and long paths both exist)

Input 3: "AAA", "ZZZ", ["AAA", "ZZZ"]

Output 3: Crash, falsey message, or no output (just don't output "AAAZZZ" or something that could be confused for a path)

Input 4: "AAA", "ZZZ", ["AAA", "AAB", "ABZ", "BZZ", "AAY", "AYZ", "YZZ", "ZZZ"],

Output 4: "AAABZZZ" OR "AAAYZZZ", but you must explain what rule decided which one to output (consistent behavior that follows your chosen rule)

Input 5: "AAA", "AAA", ["AAA", "ABA", "AAB", "BAA"],

Output 5: "AAABAAA" (Test case where initial code == terminal code, but other codes should be included in result)

Input 6: "AAA", "AAA", ["AAA", "ABA"],

Output 6: "AAA" ("AAABAAA" is not valid because "AAB" and "BAA" are 3 letter substrings contained in the answer which are not part of the valid set of country codes)

Input 7: "ISL", "ERI",

["AFG", "AHO", "AIA", "ALB", "ALG", "AND", "ANG", "ANT", "ARG", "ARM", "ARU", "ASA", "AUS", "AUT", "AZE", "BAH", "BAN", "BAR", "BDI", "BEL", "BEN", "BER", "BHU", "BIH", "BIZ", "BLR", "BOL", "BOT", "BRA", "BRN", "BRU", "BUL", "BUR", "CAF", "CAM", "CAN", "CAY", "CGO", "CHA", "CHI", "CHN", "CIV", "CMR", "COD", "COK", "COL", "COM", "CPV", "CRC", "CRO", "CUB", "CYP", "CZE", "DEN", "DJI", "DMA", "DOM", "ECU", "EGY", "ERI", "ESA", "ESP", "EST", "ETH", "FAR", "FGU", "FIJ", "FIN", "FLK", "FPO", "FRA", "FSM", "GAB", "GAM", "GBR", "GBS", "GEO", "GEQ", "GER", "GHA", "GIB", "GRE", "GRL", "GRN", "GUA", "GUD", "GUI", "GUM", "GUY", "HAI", "HEL", "HKG", "HON", "HUN", "INA", "IND", "IRI", "IRL", "IRQ", "ISL", "ISR", "ISV", "ITA", "IVB", "JAM", "JOR", "JPN", "KAZ", "KEN", "KGZ", "KIR", "KOR", "KSA", "KUW", "LAO", "LAT", "LBA", "LBR", "LCA", "LES", "LIB", "LIE", "LTU", "LUX", "MAC", "MAD", "MAR", "MAS", "MAW", "MAY", "MDA", "MDV", "MEX", "MGL", "MGO", "MKD", "MLI", "MLT", "MNT", "MON", "MOZ", "MRI", "MRT", "MSH", "MTN", "MYA", "NAM", "NCA", "NCD", "NED", "NEP", "NFI", "NGR", "NIG", "NIU", "NMA", "NOR", "NRU", "NZL", "OMA", "PAK", "PAN", "PAR", "PER", "PHI", "PLE", "PLW", "PNG", "POL", "POR", "PRK", "PUR", "QAT", "REU", "ROU", "RSA", "RUS", "RWA", "SAM", "SEN", "SEY", "SIN", "SKN", "SLE", "SLO", "SMR", "SOL", "SOM", "SPM", "SRB", "SRI", "STP", "SUD", "SUI", "SUR", "SVK", "SWE", "SWZ", "SYR", "TAN", "TGA", "THA", "TJK", "TKM", "TKS", "TLS", "TOG", "TPE", "TTO", "TUN", "TUR", "TUV", "UAE", "UGA", "UKR", "URU", "USA", "UZB", "VAN", "VEN", "VIE", "VIN", "WAF", "YEM", "ZAM", "ZIM"]

Output 7: ISLESTPERI (real world test case: IOC codes ISL -> SLE -> LES -> EST -> STP -> TPE -> PER -> ERI corresponding to Iceland -> Sierra Leone -> Lesotho -> Estonia -> Sao Tome and Principe -> Republic of China -> Peru -> Eritrea)

Input 8: USA, USA,

["ABW", "AFG", "AGO", "AIA", "ALA", "ALB", "AND", "ARE", "ARG", "ARM", "ASM", "ATA", "ATF", "ATG", "AUS", "AUT", "AZE", "BDI", "BEL", "BEN", "BES", "BFA", "BGD", "BGR", "BHR", "BHS", "BIH", "BLM", "BLR", "BLZ", "BMU", "BOL", "BRA", "BRB", "BRN", "BTN", "BVT", "BWA", "CAF", "CAN", "CCK", "CHE", "CHL", "CHN", "CIV", "CMR", "COD", "COG", "COK", "COL", "COM", "CPV", "CRI", "CUB", "CUW", "CXR", "CYM", "CYP", "CZE", "DEU", "DJI", "DMA", "DNK", "DOM", "DZA", "ECU", "EGY", "ERI", "ESH", "ESP", "EST", "ETH", "FIN", "FJI", "FLK", "FRA", "FRO", "FSM", "GAB", "GBR", "GEO", "GGY", "GHA", "GIB", "GIN", "GLP", "GMB", "GNB", "GNQ", "GRC", "GRD", "GRL", "GTM", "GUF", "GUM", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN", "IDN", "IMN", "IND", "IOT", "IRL", "IRN", "IRQ", "ISL", "ISR", "ITA", "JAM", "JEY", "JOR", "JPN", "KAZ", "KEN", "KGZ", "KHM", "KIR", "KNA", "KOR", "KWT", "LAO", "LBN", "LBR", "LBY", "LCA", "LIE", "LKA", "LSO", "LTU", "LUX", "LVA", "MAC", "MAF", "MAR", "MCO", "MDA", "MDG", "MDV", "MEX", "MHL", "MKD", "MLI", "MLT", "MMR", "MNE", "MNG", "MNP", "MOZ", "MRT", "MSR", "MTQ", "MUS", "MWI", "MYS", "MYT", "NAM", "NCL", "NER", "NFK", "NGA", "NIC", "NIU", "NLD", "NOR", "NPL", "NRU", "NZL", "OMN", "PAK", "PAN", "PCN", "PER", "PHL", "PLW", "PNG", "POL", "PRI", "PRK", "PRT", "PRY", "PSE", "PYF", "QAT", "REU", "ROU", "RUS", "RWA", "SAU", "SDN", "SEN", "SGP", "SGS", "SHN", "SJM", "SLB", "SLE", "SLV", "SMR", "SOM", "SPM", "SRB", "SSD", "STP", "SUR", "SVK", "SVN", "SWE", "SWZ", "SXM", "SYC", "SYR", "TCA", "TCD", "TGO", "THA", "TJK", "TKL", "TKM", "TLS", "TON", "TTO", "TUN", "TUR", "TUV", "TWN", "TZA", "UGA", "UKR", "UMI", "URY", "USA", "UZB", "VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF", "WSM", "YEM", "ZAF", "ZMB", "ZWE"]

Output 8: "USAUSA" (real world test case: ISO3166-Alpha-3 codes representing the path USA -> SAU -> AUS -> USA corresponding to United States -> Saudi Arabia -> Australia -> United States)


All country codes for the real world examples was taken from https://datahub.io/core/country-codes#data if you want to play with it more. The paths were a lot shorter and less interesting than I thought they'd be when I started this question (I guess the country codes don't populate the space of 3 letter strings densely enough), but someone else may find something interesting to do with them.

Reference Code: In case you prefer code you can play with over written test cases (or simply want to play with various paths but don't want to solve the challenge), here's some reference (ungolfed) code that solves all test cases quickly.

def pathfinder_helper(initial_code, terminal_code, valid_codes):
    if initial_code != terminal_code:
         if initial_code[1:] == terminal_code[:-1]:
            return [initial_code, terminal_code]

    if not valid_codes:
        if initial_code == terminal_code:
            return [initial_code]
        return None

    best_path = None
    for intermediate_code in valid_codes:
        # Pure speed optimization, can be left out and be "correct" but will be super slow on cases 7 and 8
        if initial_code[1:] != intermediate_code[:-1]:

        initial_intermediate_path = pathfinder_helper(initial_code, intermediate_code, valid_codes - {intermediate_code})
        intermediate_terminal_path = pathfinder_helper(intermediate_code, terminal_code, valid_codes - {intermediate_code})

        if initial_intermediate_path and intermediate_terminal_path:
            # Longer paths preferred
            if (best_path is None) or len(initial_intermediate_path + intermediate_terminal_path[1:]) >= len(best_path):
                if best_path and len(initial_intermediate_path + intermediate_terminal_path[1:]) == len(best_path):
                    # If lengths equal, use sort order (lexicographic)
                    if initial_intermediate_path + intermediate_terminal_path[1:] < best_path:
                        best_path = initial_intermediate_path + intermediate_terminal_path[1:]
                    best_path = initial_intermediate_path + intermediate_terminal_path[1:]
    return best_path

def pathfinder(initial_code, terminal_code, valid_codes):
    path = pathfinder_helper(initial_code, terminal_code, valid_codes - {initial_code, terminal_code})
    if path:
        return ''.join([path[0]] + [code[-1] for code in path[1:]])

print("Case 0:", pathfinder("AAA", "AAA", {"AAA"}))
print("Case 1:", pathfinder("AAA", "ZZZ", {"AAA", "AAZ", "AZZ", "ZZZ"}))
print("Case 2:", pathfinder("AAA", "ZZZ", {"AAA", "AAZ", "AZZ", "ZZZ", "AAB", "ABB", "BBB", "BBZ", "BZZ", "ZZZ"}))
print("Case 3:", pathfinder("AAA", "ZZZ", {"AAA", "ZZZ"}))
print("Case 4:", pathfinder("AAA", "ZZZ", {"AAA", "AAB", "ABZ", "BZZ", "AAY", "AYZ", "YZZ", "ZZZ"}))
print("Case 5:", pathfinder("AAA", "AAA", {"AAA", "ABA", "AAB", "BAA"}))
print("Case 6:", pathfinder("AAA", "AAA", {"AAA", "ABA"}))
print("Case 7:", pathfinder("ISL", "ERI", {"AFG", "AHO", "AIA", "ALB", "ALG", "AND", "ANG", "ANT", "ARG", "ARM", "ARU", "ASA", "AUS", "AUT", "AZE", "BAH", "BAN", "BAR", "BDI", "BEL", "BEN", "BER", "BHU", "BIH", "BIZ", "BLR", "BOL", "BOT", "BRA", "BRN", "BRU", "BUL", "BUR", "CAF", "CAM", "CAN", "CAY", "CGO", "CHA", "CHI", "CHN", "CIV", "CMR", "COD", "COK", "COL", "COM", "CPV", "CRC", "CRO", "CUB", "CYP", "CZE", "DEN", "DJI", "DMA", "DOM", "ECU", "EGY", "ERI", "ESA", "ESP", "EST", "ETH", "FAR", "FGU", "FIJ", "FIN", "FLK", "FPO", "FRA", "FSM", "GAB", "GAM", "GBR", "GBS", "GEO", "GEQ", "GER", "GHA", "GIB", "GRE", "GRL", "GRN", "GUA", "GUD", "GUI", "GUM", "GUY", "HAI", "HEL", "HKG", "HON", "HUN", "INA", "IND", "IRI", "IRL", "IRQ", "ISL", "ISR", "ISV", "ITA", "IVB", "JAM", "JOR", "JPN", "KAZ", "KEN", "KGZ", "KIR", "KOR", "KSA", "KUW", "LAO", "LAT", "LBA", "LBR", "LCA", "LES", "LIB", "LIE", "LTU", "LUX", "MAC", "MAD", "MAR", "MAS", "MAW", "MAY", "MDA", "MDV", "MEX", "MGL", "MGO", "MKD", "MLI", "MLT", "MNT", "MON", "MOZ", "MRI", "MRT", "MSH", "MTN", "MYA", "NAM", "NCA", "NCD", "NED", "NEP", "NFI", "NGR", "NIG", "NIU", "NMA", "NOR", "NRU", "NZL", "OMA", "PAK", "PAN", "PAR", "PER", "PHI", "PLE", "PLW", "PNG", "POL", "POR", "PRK", "PUR", "QAT", "REU", "ROU", "RSA", "RUS", "RWA", "SAM", "SEN", "SEY", "SIN", "SKN", "SLE", "SLO", "SMR", "SOL", "SOM", "SPM", "SRB", "SRI", "STP", "SUD", "SUI", "SUR", "SVK", "SWE", "SWZ", "SYR", "TAN", "TGA", "THA", "TJK", "TKM", "TKS", "TLS", "TOG", "TPE", "TTO", "TUN", "TUR", "TUV", "UAE", "UGA", "UKR", "URU", "USA", "UZB", "VAN", "VEN", "VIE", "VIN", "WAF", "YEM", "ZAM", "ZIM"}))
print("Case 8:", pathfinder("USA", "USA", {"ABW", "AFG", "AGO", "AIA", "ALA", "ALB", "AND", "ARE", "ARG", "ARM", "ASM", "ATA", "ATF", "ATG", "AUS", "AUT", "AZE", "BDI", "BEL", "BEN", "BES", "BFA", "BGD", "BGR", "BHR", "BHS", "BIH", "BLM", "BLR", "BLZ", "BMU", "BOL", "BRA", "BRB", "BRN", "BTN", "BVT", "BWA", "CAF", "CAN", "CCK", "CHE", "CHL", "CHN", "CIV", "CMR", "COD", "COG", "COK", "COL", "COM", "CPV", "CRI", "CUB", "CUW", "CXR", "CYM", "CYP", "CZE", "DEU", "DJI", "DMA", "DNK", "DOM", "DZA", "ECU", "EGY", "ERI", "ESH", "ESP", "EST", "ETH", "FIN", "FJI", "FLK", "FRA", "FRO", "FSM", "GAB", "GBR", "GEO", "GGY", "GHA", "GIB", "GIN", "GLP", "GMB", "GNB", "GNQ", "GRC", "GRD", "GRL", "GTM", "GUF", "GUM", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN", "IDN", "IMN", "IND", "IOT", "IRL", "IRN", "IRQ", "ISL", "ISR", "ITA", "JAM", "JEY", "JOR", "JPN", "KAZ", "KEN", "KGZ", "KHM", "KIR", "KNA", "KOR", "KWT", "LAO", "LBN", "LBR", "LBY", "LCA", "LIE", "LKA", "LSO", "LTU", "LUX", "LVA", "MAC", "MAF", "MAR", "MCO", "MDA", "MDG", "MDV", "MEX", "MHL", "MKD", "MLI", "MLT", "MMR", "MNE", "MNG", "MNP", "MOZ", "MRT", "MSR", "MTQ", "MUS", "MWI", "MYS", "MYT", "NAM", "NCL", "NER", "NFK", "NGA", "NIC", "NIU", "NLD", "NOR", "NPL", "NRU", "NZL", "OMN", "PAK", "PAN", "PCN", "PER", "PHL", "PLW", "PNG", "POL", "PRI", "PRK", "PRT", "PRY", "PSE", "PYF", "QAT", "REU", "ROU", "RUS", "RWA", "SAU", "SDN", "SEN", "SGP", "SGS", "SHN", "SJM", "SLB", "SLE", "SLV", "SMR", "SOM", "SPM", "SRB", "SSD", "STP", "SUR", "SVK", "SVN", "SWE", "SWZ", "SXM", "SYC", "SYR", "TCA", "TCD", "TGO", "THA", "TJK", "TKL", "TKM", "TLS", "TON", "TTO", "TUN", "TUR", "TUV", "TWN", "TZA", "UGA", "UKR", "UMI", "URY", "USA", "UZB", "VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF", "WSM", "YEM", "ZAF", "ZMB", "ZWE"}))
  • 3
    \$\begingroup\$ welcome to PPCG! this is a nice idea for a challenge, and well-specified for a first one. If you have doubts about a challenge (or even if you don't), you can post it in the sandbox to get feedback so it doesn't get downvoted into oblivion or closed. I hope you enjoy your time on the site! \$\endgroup\$
    – Giuseppe
    Commented May 10, 2019 at 18:19
  • 8
    \$\begingroup\$ Country codes, take me home, to the place I belong \$\endgroup\$
    – 12Me21
    Commented May 10, 2019 at 18:25
  • \$\begingroup\$ @Giuseppe, thanks for the feedback. The only thing I wasn't sure about was specifying the output format as a string which is constructed in a way I can't figure out how to express clearly (although hopefully the test cases make it clear). Allowing output directly as [RUS, USA, SAM] might be better, but the current version actually matches the game as my family plays it (although we do go for shortest, not longest). Do you feel that I should make output more flexible or do you think its ok as it is? \$\endgroup\$ Commented May 10, 2019 at 18:33
  • \$\begingroup\$ Nice challenge but 2 pointers: Your introduction is too long-winded and, largely, irrelevant to the challenge - please consider editing it down. Input validation generally doesn't go down well; I'd suggest guaranteeing that there will always be a valid path. Welcome to the site :) \$\endgroup\$
    – Shaggy
    Commented May 10, 2019 at 18:40
  • 2
    \$\begingroup\$ @ChasBrown Good Point. I will remove that constraint altogether. It made more sense with the original long-winded introduction I had, but from a pure technical side there's not much justification and I think I don't want to have to try to adjudicate "good deterministic" from "bad deterministic" \$\endgroup\$ Commented May 11, 2019 at 0:22

5 Answers 5


Python 2, 119 bytes

def f(s,e,c):
 r=max([s[0]+f(p,e,c-{p})for p in c-{s}if s[1:]==p[:2]]+[e]*(s==e)+['!'],key=len)
 return[r,'!']['!'in r]

Try it online!

Takes country codes as a set of strings; returns longest path or ! if no such path exists.


Jelly, 29 bytes


Try it online!

Golfy, but inefficient answer that generates all combinations of all power sets of the country code set minus the start and end, and then checks which ones fit the rules. A dyadic link that takes as its left argument the set of codes and its right argument the end and start in that order. Returns 0 if no path exists. Otherwise returns the longest path, and if there is more than one, the last as determined by the order of the input set.

Jelly, 42 43 bytes


Try it online!

A full program that takes three arguments: the starting country in a nested list, the final country and the list of country codes. Returns a Jelly string of the longest path if one exists with the sort order determined by the reverse of the listing of the country codes. If no valid path exists, returns 0 followed by the last letter of the destination. Works recursively, and handles longer cases relatively efficiently.


Retina, 108 bytes


Try it online! Link includes test suite. Takes input in the order set, terminal, initial. Explanation: Works by generating all possible paths, filtering on those that include the destination, and taking the longest. Explanation:


Repeat the command until it does nothing (because there are no more matches).


Operate only on lines whose chain can be extended.


List all of the new possible chains.


List all of the chains that include the terminal (cut to the length of the terminal).


Sort in ascending order of length, then reverse the list.


Take the first. In the case of a tie-break, the last to be generated wins; if the set is in lexicographic order then this will be the last in lexicographic order.


JavaScript (ES6), 106 bytes

Takes input as (terminal)(initial,[array of codes]). Returns \$0\$ if there's no solution.


Try it online!


(t, S = 0) =>         // t = terminal code; S = best string, initialized to 0
  g = (               // g is a recursive function taking:
    s,                //   s   = previous code (or initial code on the first call)
    a,                //   a[] = array of codes
    r = s             //   r   = current result string, initialized to the first code
  ) =>                //
    S =               // this code will eventually update S
    a.map(w =>        // for each word w in a[]:
      s[0] + w ==     //   the test w[0] + w[1] == s[1] + s[2] can also be processed
      s + w[2]        //   as s[0] + (w[0] + w[1]) + w[2] == s[0] + (s[1] + s[2]) + w[2]
      &               //   and therefore as s[0] + w == s + w[2]
      w != s &&       //   if the above test is true and w is not equal to s:
      g(              //   do a recursive call to g:
        w,            //     use w as the previous code
        a.filter(s => //     using a[], create a new array:
          s != w      //       where w is removed
        ),            //     end of filter()
        r + w[2]      //     append w[2] to r
      )               //   end of recursive call
    ) |               // end of map()
    s != t ||         // if s is not equal to t
    S[r.length] ?     // or S is longer than r:
      S               //   leave S unchanged
    :                 // else:
      r               //   update it to r

Haskell, 102 95 bytes

import Data.Lists
f l u@(s:t)e=argmax(1<$)$"":[e|e==u]++[s:f(l\\[w])w e|w<-l,t==take 2w,u/=w]

Returns an empty string if no path exists.

As Data.Lists is not installed on TIO, I'm providing a definition for argmax. I'm still importing Data.List for \\, so the code on TIO scores one byte less. [Try it online!]Try it online!


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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