Browse Source

Updating castle variations method to COUNT and construct

master
Charles Reid 7 years ago
parent
commit
b4a14b1b7c
  1. 263
      scratch/Round4_500-510/502/castle_variations.py
  2. 6
      scratch/Round4_500-510/502/convex_castles.py

263
scratch/Round4_500-510/502/castle_variations.py

@ -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()

6
scratch/Round4_500-510/502/convex_castles.py

@ -17,7 +17,6 @@ where there is already one R. @@ -17,7 +17,6 @@ where there is already one R.
The castle variations are in another file.
Pseudocode:
main():
@ -28,8 +27,6 @@ main(): @@ -28,8 +27,6 @@ main():
append variations to solutions
TODO:
This program only constructs convex castles.
@ -49,6 +46,9 @@ def main(): @@ -49,6 +46,9 @@ def main():
print("Number of convex castles:")
print("F(%d,%d) = %d"%( W, H, len(convex_castles)) )
for convex_castle in convex_castles:
print(convex_castle)
### for i,castle in enumerate(convex_castles):
### castle_variations = construct_castle_variations(W, H, castle)
### if(i is 0):

Loading…
Cancel
Save