task

Write a program that takes four digits, either from user input or by random generation, and computes arithmetic expressions following the rules of the 24 game.

Show examples of solutions generated by the program.



Related task

   Arithmetic Evaluator


 
/* ARM assembly Raspberry PI  */
/*  program game24Solver.s   */ 
 
/* REMARK 1 : this program use routines in a include file 
   see task Include a file language arm assembly 
   for the routine affichageMess conversion10 
   see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes                       */
/************************************/
.include "../constantes.inc"
.equ STDIN,      0       @ Linux input console
.equ READ,       3       @ Linux syscall
.equ NBDIGITS,   4       @ digits number
.equ TOTAL,      24
.equ BUFFERSIZE, 80
 
/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessRules:        .ascii "24 Game\n"
                    .ascii "The program will display four randomly-generated \n"
                    .asciz "single-digit numbers and search a solution for a total to 24\n\n"
 
szMessDigits:       .asciz "The four digits are @ @ @ @ and the score is 24. \n"
szMessOK:           .asciz "Solution : \n"
szMessNotOK:        .asciz "No solution for this problem !! \n"
szMessNewGame:      .asciz "New game (y/n) ? \n"
szCarriageReturn:   .asciz "\n"
.align 4
iGraine:            .int 123456
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
sZoneConv:        .skip 24
sBuffer:          .skip BUFFERSIZE
iTabDigit:        .skip 4 * NBDIGITS @ digits table
iTabOperand1:     .skip 4 * NBDIGITS @ operand 1 table 
iTabOperand2:     .skip 4 * NBDIGITS @ operand 2 table
iTabOperation:    .skip 4 * NBDIGITS @ operator table
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main 
main:                                 @ entry of program 
 
    ldr r0,iAdrszMessRules            @ display rules
    bl affichageMess
1:
    mov r3,#0
    ldr r12,iAdriTabDigit
    ldr r5,iAdrszMessDigits
2:                                    @ loop generate random digits 
    mov r0,#8
    bl genereraleas 
    add r0,r0,#1
    str r0,[r12,r3,lsl #2]            @ store in table
    ldr r1,iAdrsZoneConv
    bl conversion10                   @ call decimal conversion
    mov r2,#0
    strb r2,[r1,r0]                   @ reduce size display area with zéro final
    mov r0,r5
    ldr r1,iAdrsZoneConv              @ insert conversion in message
    bl strInsertAtCharInc
    mov r5,r0
    add r3,r3,#1
    cmp r3,#NBDIGITS                  @ end ?
    blt 2b                            @ no -> loop
    mov r0,r5
    bl affichageMess
 
    mov r0,#0                         @ start leval
    mov r1,r12                        @ address digits table
    bl searchSoluce
    cmp r0,#-1                        @ solution ?
    bne 3f                            @ no 
    ldr r0,iAdrszMessOK
    bl affichageMess
    bl writeSoluce                    @ yes -> write solution in buffer 
    ldr r0,iAdrsBuffer                @ and display buffer
    bl affichageMess
    b 10f
3:                                    @ display message no solution
    ldr r0,iAdrszMessNotOK
    bl affichageMess
 
 
10:                                   @ display new game ?
    ldr r0,iAdrszCarriageReturn
    bl affichageMess
    ldr r0,iAdrszMessNewGame
    bl affichageMess
    bl saisie
    cmp r0,#'y'
    beq 1b
    cmp r0,#'Y'
    beq 1b
 
100:                                  @ standard end of the program 
    mov r0, #0                        @ return code
    mov r7, #EXIT                     @ request to exit program
    svc #0                            @ perform the system call
 
iAdrszCarriageReturn:     .int szCarriageReturn
iAdrszMessRules:          .int szMessRules
iAdrszMessDigits:         .int szMessDigits
iAdrszMessNotOK:          .int szMessNotOK
iAdrszMessOK:             .int szMessOK
iAdrszMessNewGame:        .int szMessNewGame
iAdrsZoneConv:            .int sZoneConv
iAdriTabDigit:            .int iTabDigit
/******************************************************************/
/*            recherche solution                                       */ 
/******************************************************************/
/* r0 level   */
/* r1 table value address */
/* r0 return -1 if ok     */
searchSoluce:
    push {r1-r12,lr}                @ save registers
    sub sp,#4* NBDIGITS             @ reserve size new digits table
    mov fp,sp                       @ frame pointer = address stack
    mov r10,r1                      @ save table
    add r9,r0,#1                    @ new  level
    rsb r3,r9,#NBDIGITS             @ last element digits table
    ldr r4,[r1,r3,lsl #2]           @ load last element
    cmp r4,#TOTAL                   @ equal to total to search ?
    bne 0f                          @ no
    cmp r9,#NBDIGITS                @ all digits are used ?
    bne 0f                          @ no
    mov r0,#-1                      @ yes -> it is ok -> end
    b 100f
0:
    mov r5,#0                       @ indice loop 1
1:                                  @ begin loop 1
    cmp r5,r3
    bge 9f
    ldr r4,[r10,r5,lsl #2]          @ load first operand
    ldr r8,iAdriTabOperand1
    str r4,[r8,r9,lsl #2]           @ and store in operand1 table
    add r6,r5,#1                    @ indice loop 2
2:                                  @ begin loop 2
    cmp r6,r3
    bgt 8f
    ldr r12,[r10,r6,lsl #2]         @ load second operand
    ldr r8,iAdriTabOperand2
    str r12,[r8,r9,lsl #2]          @ and store in operand2 table
    mov r7,#0   @ k
    mov r8,#0   @ n
3:  
    cmp r7,r5
    beq 4f
    cmp r7,r6
    beq 4f
    ldr r0,[r10,r7,lsl #2]          @ copy other digits in new table on stack
    str r0,[fp,r8,lsl #2]
    add r8,r8,#1
4:
    add r7,r7,#1
    cmp r7,r3
    ble 3b
 
    add r7,r4,r12                   @ addition test
    str r7,[fp,r8,lsl #2]           @ store result of addition
    mov r7,#'+'
    ldr r0,iAdriTabOperation
    str r7,[r0,r9,lsl #2]           @ store operator
    mov r0,r9                       @ pass new level
    mov r1,fp                       @ pass new table address on stack
    bl searchSoluce
    cmp r0,#0
    blt 100f
                                    @ soustraction test
    cmp r4,r12
    subgt r7,r4,r12
    suble r7,r12,r4
    str r7,[fp,r8,lsl #2]
    mov r7,#'-'
    ldr r0,iAdriTabOperation
    str r7,[r0,r9,lsl #2]
    mov r0,r9
    mov r1,fp
    bl searchSoluce
    cmp r0,#0
    blt 100f
 
    mul r7,r4,r12                    @ multiplication test
    str r7,[fp,r8,lsl #2]
    mov r7,#'*'
    //vidregtit mult
    ldr r0,iAdriTabOperation
    str r7,[r0,r9,lsl #2]
    mov r0,r9
    mov r1,fp
    bl searchSoluce
    cmp r0,#0
    blt 100f
5:                                    @ division test
    push {r1-r3}
    mov r0,r4
    mov r1,r12
    bl division
   // mov r7,r9
    cmp r3,#0
    bne 6f
    str r2,[fp,r8,lsl #2]
    mov r7,#'/'
    ldr r0,iAdriTabOperation
    str r7,[r0,r9,lsl #2]
    mov r0,r9
    mov r1,fp
    bl searchSoluce
    b 7f
6:
    mov r0,r12
    mov r1,r4
    bl division
    cmp r3,#0
    bne 7f
    str r2,[fp,r8,lsl #2]
    mov r7,#'/'
    ldr r0,iAdriTabOperation
    str r7,[r0,r9,lsl #2]
    mov r0,r9
    mov r1,fp
    bl searchSoluce
7:
    pop {r1-r3}
    cmp r0,#0
    blt 100f
 
    add r6,r6,#1                      @ increment indice loop 2
    b 2b
 
8:
    add r5,r5,#1                      @ increment indice loop 1
    b 1b
9:
 
100:
    add sp,#4* NBDIGITS               @ stack alignement
    pop {r1-r12,lr}
    bx lr                             @ return 
iAdriTabOperand1:         .int iTabOperand1
iAdriTabOperand2:         .int iTabOperand2
iAdriTabOperation:        .int iTabOperation
/******************************************************************/
/*            write solution                                      */ 
/******************************************************************/
writeSoluce:
    push {r1-r12,lr}            @ save registers
    ldr r6,iAdriTabOperand1
    ldr r7,iAdriTabOperand2
    ldr r8,iAdriTabOperation
    ldr r10,iAdrsBuffer
    mov r4,#0                    @ buffer indice
    mov r9,#1
1:
    ldr r5,[r6,r9,lsl #2]       @ operand 1
    ldr r11,[r7,r9,lsl #2]       @ operand  2
    ldr r12,[r8,r9,lsl #2]       @ operator
    cmp r12,#'-'
    beq 2f
    cmp r12,#'/'
    beq 2f
    b 3f
2:                               @ if division or soustraction
    cmp r5,r11                   @ reverse operand if operand 1 is < operand 2
    movlt r2,r5
    movlt r5,r11
    movlt r11,r2
3:                               @ conversion operand 1 = r0
    mov r0,r5
    mov r1,#10
    bl division
    cmp r2,#0
    addne r2,r2,#0x30
    strneb r2,[r10,r4]
    addne r4,r4,#1
    add r3,r3,#0x30
    strb r3,[r10,r4]
    add r4,r4,#1
    ldr r2,[r7,r9,lsl #2]
 
    strb r12,[r10,r4]           @ operator
    add r4,r4,#1
 
    mov r0,r11                  @ conversion operand  2
    mov r1,#10
    bl division
    cmp r2,#0
    addne r2,r2,#0x30
    strneb r2,[r10,r4]
    addne r4,r4,#1
    add r3,r3,#0x30
    strb r3,[r10,r4]
    add r4,r4,#1
 
    mov r0,#'='
    str r0,[r10,r4]             @ conversion sous total
    add r4,r4,#1
    cmp r12,#'+'
    addeq r0,r5,r11
    cmp r12,#'-'
    subeq r0,r5,r11
    cmp r12,#'*'
    muleq r0,r5,r11
    cmp r12,#'/'
    udiveq r0,r5,r11
 
    mov r1,#10
    bl division
    cmp r2,#0
    addne r2,r2,#0x30
    strneb r2,[r10,r4]
    addne r4,r4,#1
    add r3,r3,#0x30
    strb r3,[r10,r4]
    add r4,r4,#1
    mov r0,#'\n'
    str r0,[r10,r4]
    add r4,r4,#1
 
    add r9,#1
    cmp r9,#NBDIGITS
    blt 1b
    mov r1,#0
    strb r1,[r10,r4]            @ store 0 final
 
100:
    pop {r1-r12,lr}
    bx lr                       @ return 
iAdrsBuffer:         .int sBuffer
 
/******************************************************************/
/*            string entry                                       */ 
/******************************************************************/
/* r0 return the first character of human entry */
saisie:
    push {r1-r7,lr}        @ save registers
    mov r0,#STDIN          @ Linux input console
    ldr r1,iAdrsBuffer     @ buffer address 
    mov r2,#BUFFERSIZE     @ buffer size 
    mov r7,#READ           @ request to read datas
    svc 0                  @ call system
    ldr r1,iAdrsBuffer     @ buffer address 
    ldrb r0,[r1]           @ load first character
100:
    pop {r1-r7,lr}
    bx lr                   @ return 
/***************************************************/
/*   Generation random number                  */
/***************************************************/
/* r0 contains limit  */
genereraleas:
    push {r1-r4,lr}         @ save registers 
    ldr r4,iAdriGraine
    ldr r2,[r4]
    ldr r3,iNbDep1
    mul r2,r3,r2
    ldr r3,iNbDep2
    add r2,r2,r3
    str r2,[r4]             @ maj de la graine pour l appel suivant 
    cmp r0,#0
    beq 100f
    add r1,r0,#1            @ divisor
    mov r0,r2               @ dividende
    bl division
    mov r0,r3               @ résult = remainder
 
100:                        @ end function
    pop {r1-r4,lr}          @ restaur registers
    bx lr                   @ return
/*****************************************************/
iAdriGraine: .int iGraine
iNbDep1:     .int 0x343FD
iNbDep2:     .int 0x269EC3 
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"
 
 