×
Samples Blogs Make Payment About Us Reviews 4.9/5 Order Now

Bulgarian Solitaire ARM Assembly Solution Guide

June 28, 2024
Rehana Magnus
Rehana Magnus
🇨🇦 Canada
Assembly Language
Rehana Magnus, PhD in Computer Science from the esteemed Acadia Institute of Technology, Canada. With 6 years of experience, specializes in assembly language programming. Proficient in low-level coding, optimizing performance, and enhancing system functionality.
Key Topics
  • Instructions
    • Objective
  • Requirements and Specifications
Tip of the day
Use modular coding in Verilog assignments by breaking the design into smaller modules. This improves readability, simplifies debugging, and allows for easier testing and reuse of code components in larger designs.
News
In 2024, Visual Studio Code now offers enhanced GitHub Copilot integration for faster, while PyCharm has improved debugging and testing tools, making it ideal for Python students​

Instructions

Objective

Write a Assembly language assignment program to play Bulgarian solitaire.

Requirements and Specifications

In this assignment, you will practise implementing and processing arrays in ARM Assembly by modelling the game of Bulgarian Solitaire. The game starts with 45 cards. (They need not be playing cards. Unmarked index cards work just as well.). Randomly divide them into some number of piles of random size. For example, you might start with piles of sizes 20, 5, 1, 9, and 10. In each round, you take one card from each pile, forming a new pile with these cards. For example, the sample starting configuration would be transformed into piles of sizes 19, 4, 8, 9, and 5. The solitaire is over when the piles have sizes 1, 2, 3, 4, 5, 6, 7, 8, and 9, in some order. (It can be shown that you always end up with such a configuration.) In your ARM assembler program, produce a random starting configuration and print it. Then keep applying the solitaire step and print the result. Stop when the solitaire final configuration is reached. I will leave the design of the program completely up to you but make sure that you use functions for all major tasks and keep the main function very simple .

(use it primarily to call your functions).

Screenshots of output

program-to-play-Bulgarian-solitaire-in-assembly-language (1)
program-to-play-Bulgarian-solitaire-in-assembly-language 1 (1)

Source Code

.arch armv7 .cpu cortex-a53 .data piles: .space 180 @ space to save the size of at most 45 piles startMsg: .asciz "Initial pile configuration: " nextMsg: .asciz "Next pile configuration: " .text .global main main: push {fp,lr} @ save used registers mov r0,#0 @ set arg to zero bl time @ call time(0) bl srand @ call srand(time(0)) to initialize random seed ldr r0, =piles @ pass pile address to function bl genPiles @ generate card piles ldr r0, =startMsg @ print initial message bl printf ldr r0, =piles @ pass pile address to function bl printPiles @ print initial piles b checkLast @ check if we generated the last config or loop mainLoop: ldr r0, =piles @ pass pile address to function bl newPile @ generate new card pile ldr r0, =nextMsg @ print next message bl printf ldr r0, =piles @ pass pile address to function bl printPiles @ print piles checkLast: ldr r0, =piles @ pass pile address to function bl isLastConfig @ check if it's last configuration cmp r0, #0 @ if not beq mainLoop @ try again mov r0, #0 @ return 0 pop {fp,lr} @ restore used registers bx lr @ Generate piles using 45 cards @ On entry: @ R0 = pile address genPiles: push {r4-r5,fp,lr} @ save used registers mov r4, r0 @ save address in r4 mov r5, #45 @ initially we have 45 cards genLoop: bl rand @ generate a random number udiv r1, r0, r5 @ divide random number by number of cards mul r3, r1, r5 @ multiply result by number of cards sub r0, r0, r3 @ subtract random number - multiplication to get remainder add r0, r0, #1 @ increment to get number between 1 and number of cards str r0, [r4], #4 @ save random number in pile, advance to next one sub r5, r5, r0 @ remove random number from number of cards cmp r5,#0 @ if there are still cards bne genLoop @ generate more str r5, [r4] @ save a zero to indicate end of piles pop {r4-r5,fp,lr} @ restore used registers bx lr @ return to caller @ Print the current pile configuration @ On entry: @ R0 = pile address .data numFmt: .asciz "%-3d" nline: .asciz "\n" .text printPiles: push {r4,fp,lr} @ save used registers mov r4, r0 @ save address in r4 printLoop: ldr r1, [r4], #4 @ load number from pile and advance to next one cmp r1, #0 @ if this is the last pile beq endPrint @ end printing ldr r0, =numFmt @ print number bl printf b printLoop @ repeat loop endPrint: ldr r0, =nline @ print newline bl printf pop {r4,fp,lr} @ restore used registers bx lr @ return to caller @ Generate new pile @ On entry: @ R0 = pile address newPile: push {fp,lr} @ save used registers mov r1, #0 @ new pile size is zero newLoop: ldr r2, [r0] @ load number from pile cmp r2, #0 @ if this is the last pile beq endNew @ end creating pile add r1, r1, #1 @ increment new pile size sub r2, r2, #1 @ decrement current pile size str r2, [r0] @ save updated size cmp r2, #0 @ see if pile has disappeared bne skip @ if not, skip bl compactPiles @ else, compact piles, removing this zero b newLoop @ loop reusing this position skip: add r0, r0, #4 @ advance to next pile b newLoop @ repeat loop endNew: str r1, [r0], #4 @ save new pile at the last position and advance str r2, [r0] @ save zero to indicate end of piles pop {fp,lr} @ restore used registers bx lr @ return to caller @ Compact piles by moving all piles down to the initial position, thus removing @ the initial one @ On entry: @ R0 = pile address to remove compactPiles: push {r4-r5,fp,lr} @ save used registers mov r4, r0 @ save address in r4 compactLoop: ldr r5, [r4, #4] @ load next number from pile str r5, [r4] @ save in current position cmp r5, #0 @ if this is the last pile beq endCompact @ end compacting pile add r4, r4, #4 @ advance to next pile b compactLoop @ repeat loop endCompact: pop {r4-r5,fp,lr} @ restore used registers bx lr @ return to caller @ Check if last configuration was reached @ On entry: @ R0 = pile address @ Returns: @ R0 = 1 if it's last, 0 if not isLastConfig: push {fp,lr} @ save used registers mov r1, #0 @ save mask in zero lastLoop: ldr r2, [r0] @ load number from pile cmp r2, #0 @ if this is the last pile beq checkMask @ end checking pile cmp r2, #9 @ check if number is valid bgt notLast @ if > 9, this is not the last config mov r3, #1 @ else, load 1 lsl r3, r3, r2 @ move to bit position n (1-9) orr r1, r1, r3 @ add to mask add r0, r0, #4 @ advance to next pile b lastLoop @ repeat loop checkMask: ldr r0, =0x3FE @ load mask with bit positions 1-9 set to 1 cmp r1, r0 @ if the positions 1-9 are filled bne notLast @ if not, is not the last mov r0, #1 @ else, it's the last b endCheck @ end notLast: mov r0, #0 @ not last endCheck: pop {fp,lr} @ restore used registers bx lr @ return to caller

Similar Samples