from mpi4py import MPI
def calculate_required_cards(height):
"""Calculate the number of cards required to build a pyramid of a given height."""
return (height * (3 * height + 1)) // 2
def calculate_pyramid_height_and_cards(card_count):
"""Calculate the maximum height of a pyramid and the number of cards used."""
height = 0
while True:
required_cards = calculate_required_cards(height)
if required_cards > card_count:
break
height += 1
height -= 1 # Adjust to the last valid height
required_cards = calculate_required_cards(height)
return height, required_cards
def main():
comm = MPI.COMM_WORLD
process_rank = comm.Get_rank()
total_processes = comm.Get_size()
if total_processes <= 1:
if process_rank == 0:
print("Error: At least one worker process is required.")
return 0
if process_rank == 0:
# Master process
total_cards = int(input("Enter the total number of cards: "))
remaining_cards = total_cards
pyramid_count = 0
loop_counter = 0 # To prevent infinite loops
max_attempts = 1000 # Arbitrary large number to safeguard against infinite loops
while remaining_cards > 0:
if loop_counter >= max_attempts:
print("Exceeded maximum attempts. Stopping to prevent infinite loop.")
break
# Assign work to a worker process
worker_rank = (pyramid_count % (total_processes - 1)) + 1
comm.send(remaining_cards, dest=worker_rank, tag=11)
# Receive results from the worker process
try:
pyramid_height, cards_used = comm.recv(source=worker_rank, tag=22)
except Exception as e:
print(f"Error during communication with worker {worker_rank}: {e}")
break
if cards_used == 0:
print(f"Cannot build a pyramid with the remaining {remaining_cards} cards. Stopping further attempts.")
break
print(f"Pyramid {pyramid_count + 1}: Using {cards_used} cards to build a pyramid of height {pyramid_height}.")
remaining_cards -= cards_used
pyramid_count += 1
loop_counter += 1
# Send termination signal to all worker processes
for worker_rank in range(1, total_processes):
comm.send(-1, dest=worker_rank, tag=11)
print(f"\nTotal pyramids built: {pyramid_count}")
return pyramid_count
else:
# Worker processes
while True:
try:
cards_available = comm.recv(source=0, tag=11)
except Exception as e:
print(f"Error receiving data from master process: {e}")
break
if cards_available == -1:
break # Termination signal
pyramid_height, cards_used = calculate_pyramid_height_and_cards(cards_available)
try:
comm.send((pyramid_height, cards_used), dest=0, tag=22)
except Exception as e:
print(f"Error sending data to master process: {e}")
break
if __name__ == "__main__":
result = main()
if result is not None:
print(f"Result from main function: {result}")