|
|
|
@ -1,105 +1,67 @@
@@ -1,105 +1,67 @@
|
|
|
|
|
def main(): |
|
|
|
|
#construct_castle_variations("UUUURRRRRRRRDDDD") |
|
|
|
|
construct_castle_variations("UURRRRUURRRRDDDD") |
|
|
|
|
from pprint import pprint |
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
Castle Variations |
|
|
|
|
|
|
|
|
|
Given a convex castle, find runs of consecutive Rs |
|
|
|
|
and construct all variations of this castle. |
|
|
|
|
|
|
|
|
|
This does not account for the fact that if we have |
|
|
|
|
multiple runs, variations of each run actually create |
|
|
|
|
new castles. |
|
|
|
|
|
|
|
|
|
################################################################# |
|
|
|
|
That is, if we have 13 variations from the first set |
|
|
|
|
of consecutive Rs, plus the original convex castle, |
|
|
|
|
and 15 variations from the second set, plus original, |
|
|
|
|
we actually have (13 + 1) x (15 + 1) = 224 variations. |
|
|
|
|
|
|
|
|
|
If we have n slots, and each slot j has V_j variations, |
|
|
|
|
the total number of variations on that one single |
|
|
|
|
convex castle is: |
|
|
|
|
|
|
|
|
|
def test_variations(): |
|
|
|
|
\Pi_{j=1}^{n} (V_j + 1) |
|
|
|
|
|
|
|
|
|
castle = "RRRR" |
|
|
|
|
|
|
|
|
|
h = 3 # height of this sequence of Rs |
|
|
|
|
H = 5 # max height of castle |
|
|
|
|
|
|
|
|
|
m = 4 # number of Rs |
|
|
|
|
p = 2 # number of columns |
|
|
|
|
|
|
|
|
|
ix = 0 # index at which sequence of Rs begins |
|
|
|
|
|
|
|
|
|
heights = [h] |
|
|
|
|
variants(castle, 0, p, heights, H) |
|
|
|
|
This script generates the V_j variations. |
|
|
|
|
You should be able to count them from there. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def variants(castle, which_p, max_p, heights, max_height): |
|
|
|
|
"""Construct variations of castle |
|
|
|
|
(which is a convex castle). |
|
|
|
|
def main(): |
|
|
|
|
#construct_castle_variations("UUUURRRRRRRRDDDD") |
|
|
|
|
construct_castle_variations("UURRRRUURRRRDDDD") |
|
|
|
|
|
|
|
|
|
p is the current column. |
|
|
|
|
If we have m consecutive R's, |
|
|
|
|
we have p = m-2 columns to set. |
|
|
|
|
First and last column heights are fixed. |
|
|
|
|
|
|
|
|
|
heights is a list of m-1 heights. |
|
|
|
|
The very first height is the starting height. |
|
|
|
|
The very last height is the same (and is not added). |
|
|
|
|
Implicitly, the very last R is not touched. |
|
|
|
|
If it were a different height, the variant would be a dupe. |
|
|
|
|
def construct_castle_variations(castle): |
|
|
|
|
""" |
|
|
|
|
if(which_p==max_p): |
|
|
|
|
# base case: |
|
|
|
|
# Use heights to assemble correct insertions of Us and Ds. |
|
|
|
|
# |
|
|
|
|
# Example: |
|
|
|
|
# RRRR |
|
|
|
|
# We have four columns, but only two with a variable height. |
|
|
|
|
# |
|
|
|
|
# Insert first R (at height h). Change to new height. |
|
|
|
|
# |
|
|
|
|
# Insert second R (at new height). Change to new new height. |
|
|
|
|
# |
|
|
|
|
# Insert third R (at new new height). (No new height to set - return to original height.) |
|
|
|
|
# |
|
|
|
|
# Insert last R. |
|
|
|
|
|
|
|
|
|
# Last height equals first height |
|
|
|
|
heights.append(heights[0]) |
|
|
|
|
|
|
|
|
|
buff = [] |
|
|
|
|
|
|
|
|
|
buff.append('R') |
|
|
|
|
|
|
|
|
|
for i in range(1,len(heights)): |
|
|
|
|
dh = heights[i] - heights[i-1] |
|
|
|
|
if(dh>0): |
|
|
|
|
buff.append('U'*dh) |
|
|
|
|
elif(dh<0): |
|
|
|
|
buff.append('D'*(-dh)) |
|
|
|
|
Find the index, length, and height |
|
|
|
|
of all seqences of Rs. |
|
|
|
|
""" |
|
|
|
|
# Find index, length, and height of R sequences |
|
|
|
|
runs = consecutive_Rs(castle) |
|
|
|
|
|
|
|
|
|
buff.append('R') |
|
|
|
|
H = sum([1 for m in castle if m=='U']) |
|
|
|
|
|
|
|
|
|
heights.pop() |
|
|
|
|
variant_sizes = [] |
|
|
|
|
for run_ix, run_len, run_h in runs: |
|
|
|
|
if(run_len<3): |
|
|
|
|
# Not enough Rs |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
print("Castle heights: %s"%(heights)) |
|
|
|
|
print("Castle moves: %s"%( "".join(buff) )) |
|
|
|
|
print() |
|
|
|
|
castles = [] |
|
|
|
|
heights = [run_h] |
|
|
|
|
ix = run_ix |
|
|
|
|
p = run_len - 2 |
|
|
|
|
variants(castle, castles, ix, 0, p, heights, H) |
|
|
|
|
|
|
|
|
|
variant_sizes.append(len(castles)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
|
# recursive case: |
|
|
|
|
for this_h in range(1,max_height+1): |
|
|
|
|
heights.append(this_h) |
|
|
|
|
variants(castle, which_p+1, max_p, heights, max_height) |
|
|
|
|
heights.pop() |
|
|
|
|
result = prod([j+1 for j in variant_sizes]) |
|
|
|
|
print("Total castle variations counted: %s"%(result)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
################################################################# |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def construct_castle_variations(castle): |
|
|
|
|
# Number of consecutive Rs and their index |
|
|
|
|
runs = consecutive_Rs(castle) |
|
|
|
|
|
|
|
|
|
for run in runs: |
|
|
|
|
print(run) |
|
|
|
|
print() |
|
|
|
|
|
|
|
|
|
def consecutive_Rs(castle): |
|
|
|
|
"""Find sequences of multiple Rs. |
|
|
|
|
""" |
|
|
|
|
Find sequences of multiple Rs. |
|
|
|
|
Return a tuple of pairs (x,y), |
|
|
|
|
where x is the starting index and |
|
|
|
|
y is the length of the run. |
|
|
|
@ -108,16 +70,18 @@ def consecutive_Rs(castle):
@@ -108,16 +70,18 @@ def consecutive_Rs(castle):
|
|
|
|
|
doing_run = False |
|
|
|
|
current_length = 0 |
|
|
|
|
current_index = 0 |
|
|
|
|
current_height = 0 |
|
|
|
|
for im,move in enumerate(castle): |
|
|
|
|
|
|
|
|
|
if(doing_run): |
|
|
|
|
if(move is not 'R'): |
|
|
|
|
# If not R and doing run, |
|
|
|
|
# end the current run |
|
|
|
|
runs.append((current_index, current_length)) |
|
|
|
|
runs.append((current_index, current_length, current_height)) |
|
|
|
|
doing_run = False |
|
|
|
|
current_length = 0 |
|
|
|
|
current_index = 0 |
|
|
|
|
current_height = 0 |
|
|
|
|
else: |
|
|
|
|
# If R and doing a run, |
|
|
|
|
# increment length |
|
|
|
@ -125,15 +89,142 @@ def consecutive_Rs(castle):
@@ -125,15 +89,142 @@ def consecutive_Rs(castle):
|
|
|
|
|
else: |
|
|
|
|
if(move is 'R'): |
|
|
|
|
# If R and not doing a run, |
|
|
|
|
# find the height and |
|
|
|
|
# start doing a run |
|
|
|
|
current_index = im |
|
|
|
|
doing_run = True |
|
|
|
|
current_index = im |
|
|
|
|
current_length = 1 |
|
|
|
|
for k in range(im): |
|
|
|
|
if castle[k] is 'U': |
|
|
|
|
current_height += 1 |
|
|
|
|
elif castle[k] is 'D': |
|
|
|
|
current_height -= 1 |
|
|
|
|
|
|
|
|
|
return runs |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def variants(castle, castles, ix, which_p, max_p, heights, max_height): |
|
|
|
|
""" |
|
|
|
|
Construct variations of castle |
|
|
|
|
(which is a convex castle). |
|
|
|
|
|
|
|
|
|
NOTE: |
|
|
|
|
If we are just passing in sequences of R's, |
|
|
|
|
and we have the same set of heights reoccurring, |
|
|
|
|
this function can be memoized. |
|
|
|
|
|
|
|
|
|
NOTE 2: |
|
|
|
|
This DOES NOT include/generate the original convex castle. |
|
|
|
|
|
|
|
|
|
castle is the string of moves representing |
|
|
|
|
this convex castle. |
|
|
|
|
|
|
|
|
|
castles is a container storing all castle |
|
|
|
|
variations. |
|
|
|
|
|
|
|
|
|
which_p is the current column. |
|
|
|
|
If we have m consecutive R's, |
|
|
|
|
we have p = m-2 columns to set. |
|
|
|
|
First and last column heights are fixed. |
|
|
|
|
|
|
|
|
|
max_p is the (max) number of columns whose height |
|
|
|
|
can be set (run length - 2). |
|
|
|
|
|
|
|
|
|
heights is a list of m-1 heights. |
|
|
|
|
The very first height is the starting height. |
|
|
|
|
The very last height is the same (and is not added). |
|
|
|
|
Implicitly, the very last R is not touched. |
|
|
|
|
If it were a different height, the variant would be a dupe. |
|
|
|
|
|
|
|
|
|
max_height is the maximum height this castle |
|
|
|
|
can achieve (H). |
|
|
|
|
""" |
|
|
|
|
if(which_p==max_p): |
|
|
|
|
if(sum(heights)==heights[0]*len(heights)): |
|
|
|
|
# All heights are the same |
|
|
|
|
# This is the original convex castle |
|
|
|
|
return |
|
|
|
|
else: |
|
|
|
|
# base case: |
|
|
|
|
# Use heights to assemble correct insertions of Us and Ds. |
|
|
|
|
# |
|
|
|
|
# Example: |
|
|
|
|
# RRRR |
|
|
|
|
# We have four columns, but only two with a variable height. |
|
|
|
|
# |
|
|
|
|
# Insert first R (at height h). Change to new height. |
|
|
|
|
# |
|
|
|
|
# Insert second R (at new height). Change to new new height. |
|
|
|
|
# |
|
|
|
|
# Insert third R (at new new height). (No new height to set - return to original height.) |
|
|
|
|
# |
|
|
|
|
# Insert last R. |
|
|
|
|
|
|
|
|
|
left_piece = castle[0:ix] |
|
|
|
|
right_piece = castle[ix+max_p+2:] |
|
|
|
|
|
|
|
|
|
# Last height equals first height |
|
|
|
|
heights.append(heights[0]) |
|
|
|
|
|
|
|
|
|
buff = [] |
|
|
|
|
|
|
|
|
|
buff.append('R') |
|
|
|
|
|
|
|
|
|
for i in range(1,len(heights)): |
|
|
|
|
dh = heights[i] - heights[i-1] |
|
|
|
|
if(dh>0): |
|
|
|
|
buff.append('U'*dh) |
|
|
|
|
elif(dh<0): |
|
|
|
|
buff.append('D'*(-dh)) |
|
|
|
|
|
|
|
|
|
buff.append('R') |
|
|
|
|
|
|
|
|
|
final_castle = left_piece + "".join(buff) + right_piece |
|
|
|
|
|
|
|
|
|
castles.append(final_castle) |
|
|
|
|
|
|
|
|
|
heights.pop() |
|
|
|
|
|
|
|
|
|
else: |
|
|
|
|
# recursive case: |
|
|
|
|
for this_h in range(1,max_height+1): |
|
|
|
|
heights.append(this_h) |
|
|
|
|
variants(castle, castles, ix, which_p+1, max_p, heights, max_height) |
|
|
|
|
heights.pop() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def prod(arr): |
|
|
|
|
""" |
|
|
|
|
Take the product of every element in an array. |
|
|
|
|
(Why does Python provide sum, but not prod?) |
|
|
|
|
""" |
|
|
|
|
prod = 1 |
|
|
|
|
for a in arr: |
|
|
|
|
prod *= a |
|
|
|
|
return prod |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_variations(): |
|
|
|
|
""" |
|
|
|
|
Run a quick test with a castle. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
castle = "UUURRRRUURDDD" |
|
|
|
|
|
|
|
|
|
h = 3 # height of this sequence of Rs |
|
|
|
|
H = 5 # max height of castle |
|
|
|
|
|
|
|
|
|
m = 4 # number of Rs |
|
|
|
|
p = 2 # number of columns |
|
|
|
|
|
|
|
|
|
ix = 3 # index at which sequence of Rs begins |
|
|
|
|
|
|
|
|
|
heights = [h] |
|
|
|
|
castles = [] |
|
|
|
|
variants(castle, castles, ix, 0, p, heights, H) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__=="__main__": |
|
|
|
|
#main() |
|
|
|
|
test_variations() |
|
|
|
|
main() |
|
|
|
|
#test_variations() |
|
|
|
|
|
|
|
|
|