package require struct::list
# Encoding the various expression trees that are possible
set patterns {
    {((A x B) y C) z D}
     {(A x (B y C)) z D}
     {(A x B) y (C z D)}
      {A x ((B y C) z D)}
      {A x (B y (C z D))}
}
# Encoding the various permutations of digits
set permutations [struct::list map [struct::list permutations {a b c d}] \
        {apply {v {lassign $v a b c d; list A $a B $b C $c D $d}}}]
# The permitted operations
set operations {+ - * /}

# Given a list of four integers (precondition not checked!)
# return a list of solutions to the 24 game using those four integers.
proc find24GameSolutions {values} {
    global operations patterns permutations
    set found {}
    # For each possible structure with numbers at the leaves...
    foreach pattern $patterns {
	foreach permutation $permutations {
	    set p [string map [subst {
		a [lindex $values 0].0
		b [lindex $values 1].0
		c [lindex $values 2].0
		d [lindex $values 3].0
	    }] [string map $permutation $pattern]]

            # For each possible structure with operators at the branches...
	    foreach x $operations {
		foreach y $operations {
		    foreach z $operations {
			set e [string map [subst {x $x y $y z $z}] $p]

			# Try to evaluate (div-zero is an issue!) and add it to
			# the result if it is 24
			catch {
			    if {[expr $e] == 24.0} {
				lappend found [string map {.0 {}} $e]
			    }
			}
		    }
		}
	    }
	}
    }
    return $found
}

# Wrap the solution finder into a player
proc print24GameSolutionFor {values} {
    set found [lsort -unique [find24GameSolutions $values]]
    if {![llength $found]} {
	puts "No solution possible"
    } else {
	puts "Total [llength $found] solutions (may include logical duplicates)"
        puts "First solution: [lindex $found 0]"
    }
}
print24GameSolutionFor $argv


#import std
#import nat
#import rat

tree_shapes = "n". (@vLPiYo //eql iota "n")*~ (rep"n" ~&iiiK0NlrNCCVSPTs) {0^:<>}
with_leaves = ^|DrlDrlK34SPSL/permutations ~&
with_roots  = ^DrlDrlK35dlPvVoPSPSL\~&r @lrhvdNCBvLPTo2DlS @hiNCSPtCx ~&K0=>
value       = *^ ~&v?\(@d ~&\1) ^|H\~&hthPX '+-*/'-$<sum,difference,product,quotient>
format      = *^ ~&v?\-+~&h,%[email protected]+- ^H/[email protected] *v ~&t?\~& :/`(+ --')'

game"n" "d" = format* value==("n",1)*~ with_roots/'+-*/' with_leaves/"d"*-1 tree_shapes length "d"


import "random" for Random
import "/dynamic" for Tuple, Enum, Struct

var N_CARDS = 4
var SOLVE_GOAL = 24
var MAX_DIGIT = 9

var Frac = Tuple.create("Frac", ["num", "den"])

var OpType = Enum.create("OpType", ["NUM", "ADD", "SUB", "MUL", "DIV"])

var Expr = Struct.create("Expr", ["op", "left", "right", "value"])

var showExpr // recursive function
showExpr = Fn.new { |e, prec, isRight|
    if (!e) return
    if (e.op == OpType.NUM) {
        System.write(e.value)
        return
    }
    var op = (e.op == OpType.ADD) ? " + " :
             (e.op == OpType.SUB) ? " - " :
             (e.op == OpType.MUL) ? " x " :
             (e.op == OpType.DIV) ? " / " : e.op
    if ((e.op == prec && isRight) || e.op < prec) System.write("(")
    showExpr.call(e.left, e.op, false)
    System.write(op)
    showExpr.call(e.right, e.op, true)
    if ((e.op == prec && isRight) || e.op < prec) System.write(")")
}

var evalExpr // recursive function
evalExpr = Fn.new { |e|
    if (!e) return Frac.new(0, 1)
    if (e.op == OpType.NUM) return Frac.new(e.value, 1)
    var l = evalExpr.call(e.left)
    var r = evalExpr.call(e.right)
    var res = (e.op == OpType.ADD) ? Frac.new(l.num * r.den + l.den * r.num, l.den * r.den) :
              (e.op == OpType.SUB) ? Frac.new(l.num * r.den - l.den * r.num, l.den * r.den) :
              (e.op == OpType.MUL) ? Frac.new(l.num * r.num, l.den * r.den) :
              (e.op == OpType.DIV) ? Frac.new(l.num * r.den, l.den * r.num) :
               Fiber.abort("Unknown op: %(e.op)")
    return res
}

var solve // recursive function
solve = Fn.new { |ea, len|
    if (len == 1) {
        var final = evalExpr.call(ea[0])
        if (final.num == final.den * SOLVE_GOAL && final.den != 0) {
            showExpr.call(ea[0], OpType.NUM, false)
            return true
        }
    }
    var ex = List.filled(N_CARDS, null)
    for (i in 0...len - 1) {
        for (j in i + 1...len) ex[j - 1] = ea[j]
        var node = Expr.new(OpType.NUM, null, null, 0)
        ex[i] = node
        for (j in i + 1...len) {
            node.left = ea[i]
            node.right = ea[j]
            for (k in OpType.startsFrom+1...OpType.members.count) {
                node.op = k
                if (solve.call(ex, len - 1)) return true
            }
            node.left = ea[j]
            node.right = ea[i]
            node.op = OpType.SUB
            if (solve.call(ex, len - 1)) return true
            node.op = OpType.DIV
            if (solve.call(ex, len - 1)) return true
            ex[j] = ea[j]
        }
        ex[i] = ea[i]
    }
    return false
}

var solve24 = Fn.new { |n|
    var l = List.filled(N_CARDS, null)
    for (i in 0...N_CARDS) l[i] = Expr.new(OpType.NUM, null, null, n[i])
    return solve.call(l, N_CARDS)
}

var r = Random.new()
var n = List.filled(N_CARDS, 0)
for (j in 0..9) {
    for (i in 0...N_CARDS) {
        n[i] = 1 + r.int(MAX_DIGIT)
        System.write(" %(n[i])")
    }
    System.write(":  ")
    System.print(solve24.call(n) ? "" : "No solution")
}


operators$ = "*+-/"
space$ = "                                                                                "

sub present()
	clear screen
	print "24 Game"
	print "============\n"
	print "Computer provide 4 numbers (1 to 9). With operators +, -, * and / you try to\nobtain 24."
	print "Use Reverse Polish Notation (first operand and then the operators)"
	print "For example: instead of 2 + 4, type 2 4 +\n\n"
end sub

repeat
	present()
	serie$ = sortString$(genSerie$())
	valid$ = serie$+operators$
	print "If you give up, press ENTER and the program attempts to find a solution."
	line input "Write your solution: " input$
	if input$ = "" then
		print "Thinking ... "
		res$ = explorer$()
		if res$ = "" print "Can not get 24 with these numbers.."
	else
		input$ = delSpace$(input$)
		inputSort$ = sortString$(input$)
		if (right$(inputSort$,4) <> serie$) or (len(inputSort$)<>7) then
			print "Syntax error"
		else
			result = evalInput(input$)
			print "Your solution = ",result," is ";
			if result = 24 then
				print "Correct!"
			else
				print "Wrong!"
			end if
		end if
	end if
	print "\nDo you want to try again? (press N for exit, other key to continue)"
until(upper$(left$(inkey$(),1)) = "N")

exit

sub genSerie$()
	local i, c$, s$

	print "The numbers you should use are: ";
	i = ran()
	for i = 1 to 4
		c$ = str$(int(ran(9))+1)
		print c$," ";
		s$ = s$ + c$
	next i
	print
	return s$
end sub

sub evalInput(entr$)
	local d1, d2, c$, n(4), i

	while(entr$<>"")
		c$ = left$(entr$,1)
		entr$ = mid$(entr$,2)
		if instr(serie$,c$) then
			i = i + 1
			n(i) = val(c$)
		elseif instr(operators$,c$) then
			d2 = n(i)
			n(i) = 0
			i = i - 1
			if i = 0 return
			d1 = n(i)
			n(i) = evaluator(d1, d2, c$)
		else
			print "Invalid symbol"
			return
		end if
	wend

	return n(i)

end sub

sub evaluator(d1, d2, op$)
	local t

	switch op$
		case "+": t = d1 + d2 : break
		case "-": t = d1 - d2 : break
		case "*": t = d1 * d2 : break
		case "/": t = d1 / d2 : break
	end switch

	return t
end sub

sub delSpace$(entr$)
	local n, i, s$, t$(1)

	n = token(entr$,t$()," ")

	for i=1 to n
		s$ = s$ + t$(i)
	next i
	return s$
end sub

sub sortString$(string$)
	local signal, n, fin, c$

	fin = len(string$)-1
	repeat
		signal = false
		for n = 1 to fin
			if mid$(string$,n,1) > mid$(string$,n+1,1) then
				signal = true
				c$ = mid$(string$,n,1)
				mid$(string$,n,1) = mid$(string$,n+1,1)
				mid$(string$,n+1,1) = c$
			end if
		next n
	until(signal = false)
	return string$
end sub

sub explorer$()
	local d1,d2,o3,x4,x5,x6,o7,p$,result,solution,solutions$,n

	for d1 = 1 to 4
		for d2 = 1 to 4
			for o3 = 1 to 4
				for x4 = 1 to 8
					for x5 = 1 to 8
						for x6 = 1 to 8
							for o7 = 1 to 4
								p$ = mid$(serie$,d1,1)+mid$(serie$,d2,1)+mid$(operators$,o3,1)
								p$ = p$+mid$(valid$,x4,1)+mid$(valid$,x5,1)+mid$(valid$,x6,1)
								p$ = p$+mid$(operators$,o7,1)
								if not instr(solutions$,p$) then
									if validateInput(p$) then
										result = evalInput(p$)
										if result = 24 then
											solution = solution + 1
											print "Solution: ",solution," = ";
											solutions$ = solutions$ + p$
											for n = 1 to 7
												print mid$(p$,n,1)," ";
											next n
											print
										end if
									end if
								end if
							next o7
						next x6
					next x5
				next x4
			next o3
		next d2
	next d1
	return p$
end sub

sub validateInput(e$)
	local n, inputSort$

	inputSort$ = sortString$(e$)
	if serie$ <> right$(inputSort$,4) return false
	for n=1 to 3
		if not instr(operators$,mid$(inputSort$,n,1)) then
			return false
		end if
	next n
	return true
end sub


var [const] H=Utils.Helpers;
fcn u(xs){ xs.reduce(fcn(us,s){us.holds(s) and us or us.append(s) },L()) }
var ops=u(H.combosK(3,"+-*/".split("")).apply(H.permute).flatten());
var fs=T(
   fcn f0(a,b,c,d,x,y,z){ Op(z)(Op(y)(Op(x)(a,b),c),d) }, // ((AxB)yC)zD
   fcn f1(a,b,c,d,x,y,z){ Op(y)(Op(x)(a,b),Op(z)(c,d)) }, // (AxB)y(CzD)
   fcn f2(a,b,c,d,x,y,z){ Op(z)(Op(x)(a,Op(y)(b,c)),d) }, // (Ax(ByC))zD
   fcn f3(a,b,c,d,x,y,z){ Op(x)(a,Op(z)(Op(y)(b,c),d)) }, // Ax((ByC)zD)
   fcn f4(a,b,c,d,x,y,z){ Op(x)(a,Op(y)(b,Op(z)(c,d))) }, // Ax(By(CzD))
);

var fts= // format strings for human readable formulas
  T("((d.d).d).d", "(d.d).(d.d)", "(d.(d.d)).d", "d.((d.d).d)", "d.(d.(d.d))")
  .pump(List,T("replace","d","%d"),T("replace",".","%s"));

fcn f2s(digits,ops,f){
   fts[f.name[1].toInt()].fmt(digits.zip(ops).flatten().xplode(),digits[3]);
}

fcn game24Solver(digitsString){
   digits:=digitsString.split("").apply("toFloat");
   [[(digits4,ops3,f); H.permute(digits); ops;    // list comprehension
     fs,{ try{f(digits4.xplode(),ops3.xplode()).closeTo(24,0.001) }
          catch(MathError){ False } };
     { f2s(digits4,ops3,f) }]];
}


F select_count(game_count)
   ‘selects a random number if the game_count is less than 18. otherwise chooses the winning number’
   Int t
   I game_count < 18
      t = random:(1..3)
   E
      t = 21 - game_count
   print(‘The computer chooses #.’.format(t))
   R t

F request_count()
   ‘request user input between 1,2 and 3. It will continue till either quit(q) or one of those numbers is requested.’
   V t = ‘’
   L
      X.try
         t = input(‘Your choice 1 to 3 :’)
         I Int(t) C [1, 2, 3]
            R Int(t)
         E
            print(‘Out of range, try again’)
      X.catch
         I t == ‘q’
            R 0
         E
            print(‘Invalid Entry, try again’)

F start()
   V game_count = 0
   print("Enter q to quit at any time.\nThe computer will choose first.\nRunning total is now #.".format(game_count))
   V roundno = 1
   L
      print("\nROUND #.: \n".format(roundno))
      V t = select_count(game_count)
      game_count = game_count + t
      print("Running total is now #.\n".format(game_count))
      I game_count >= 21
         print(‘So, commiserations, the computer has won!’)
         R 0
      t = request_count()
      I t == 0
         print(‘OK,quitting the game’)
         R -1
      game_count = game_count + t
      print("Running total is now #.\n".format(game_count))
      I game_count >= 21
         print(‘So, congratulations, you've won!’)
         R 1
      roundno++

V c = 0
V m = 0
L
   V o = start()
   I o == -1
      L.break
   E
      c += I o == 0 {1} E 0
      m += I o == 1 {1} E 0
   print(‘Computer wins #. game, human wins #. games’.format(c, m))
   V t = input(‘Another game?(press y to continue):’)
   I t != ‘y’
      L.break


/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program game21_64.s   */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"

.equ HITTOTAL,   21
.equ BUFFERSIZE, 10

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessRules:         .ascii "21 Game\n"
                    .ascii "21 is a two player game, the game is played by choosing a number \n"
                    .ascii "(1, 2, or 3) to be added to the running total. The game is won by\n"
                    .ascii "the player whose chosen number causes the running total to reach \n"
                    .asciz "exactly 21. The running total starts at zero.\n\n\n"

szMessHumanChoice:  .asciz "Enter your choice (1,2, 3 or type (q)uit to exit): "
szMessErrChoise:    .asciz "invalid choice.\n  "
szMessHumanBegin:   .asciz "The first move is human move.\n"
szMessPiBegin:      .asciz "The first move is Raspberry pi. \n"
szMessHumanWon:     .asciz "You won. \n"
szMessHumanLost:    .asciz "You lost. \n"
szMessTotal:        .asciz "The running total is @ \n"
szMessPiChoice:     .asciz "Raspberry choice is  @ \n"
szMessNewGame:      .asciz "New game (y/n) ? \n"
szCarriageReturn:   .asciz "\n"
.align 4
qGraine:  .quad 123456
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:        .skip 24
sBuffer:          .skip BUFFERSIZE
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                 // entry of program

    ldr x0,qAdrszMessRules
    bl affichageMess
1:
    mov x10,#0                         // total = 0
    mov x0,#100
    bl genereraleas
    cmp x0,#50
    blt 2f
    ldr x0,qAdrszMessHumanBegin        // human begin
    bl affichageMess
    b 4f
2:                                     // Rasp begin
    ldr x0,qAdrszMessPiBegin
    bl affichageMess
    mov x0,#1
3:                                    // rasp turn
    add x10,x10,x0
    ldr x1,qAdrsZoneConv
    bl conversion10                   // call decimal conversion
    ldr x0,qAdrszMessPiChoice
    ldr x1,qAdrsZoneConv              // insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess
    cmp x10,#HITTOTAL
    bne 4f
    ldr x0,qAdrszMessHumanLost
    bl affichageMess
    b 12f
4:                                    // display current total
    mov x0,x10
    ldr x1,qAdrsZoneConv
    bl conversion10                   // call decimal conversion
    ldr x0,qAdrszMessTotal
    ldr x1,qAdrsZoneConv              // insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess

5:                                    // human turn
    ldr x0,qAdrszMessHumanChoice
    bl affichageMess
    bl saisie
    cmp x0,#'q'                       // quit ?
    beq 100f
    cmp x0,#'Q'
    beq 100f
    cmp x0,#'1'
    add x9,x10,1
    csel x10,x9,x10,eq
    beq 6f
    cmp x0,#'2'
    add x9,x10,2
    csel x10,x9,x10,eq
    beq 6f
    cmp x0,#'3'
    add x9,x10,3
    csel x10,x9,x10,eq
    beq 6f
    ldr x0,qAdrszMessErrChoise
    bl affichageMess
    b 5b
6:
    cmp x10,#HITTOTAL                // total = maxi ?
    beq 11f                           // yes -> human won
    cmp x10,#5                       // else compute rasp number
    mov x9,5                         // compare total and optimun
7:
    cmp x10,x9
    ble 8f
    add x9,x9,4
    b 7b
8:
    sub x0,x9,x10                   // compute number rasp
9:                                  // control number rasp
    cmp x0,#0
    ble 10f
    cmp x0,#3
    ble 3b
10:                                  // if not ok, generate random number
    mov x0,#2
    bl genereraleas
    add x0,x0,#1
    b 3b                            // and loop

11:                                  // display human won
    ldr x0,qAdrszMessHumanWon
    bl affichageMess
12:                                 // display new game ?
    ldr x0,qAdrszCarriageReturn
    bl affichageMess
    ldr x0,qAdrszMessNewGame
    bl affichageMess
    bl saisie
    cmp x0,#'y'
    beq 1b
    cmp x0,#'Y'
    beq 1b

100:                                  // standard end of the program
    mov x0, #0                        // return code
    mov x8, #EXIT                     // request to exit program
    svc #0                            // perform the system call

qAdrszCarriageReturn:     .quad szCarriageReturn
qAdrszMessRules:          .quad szMessRules
qAdrszMessHumanBegin:     .quad szMessHumanBegin
qAdrszMessPiBegin:        .quad szMessPiBegin
qAdrszMessPiChoice:       .quad szMessPiChoice
qAdrszMessTotal:          .quad szMessTotal
qAdrszMessHumanChoice:    .quad szMessHumanChoice
qAdrszMessHumanLost:      .quad szMessHumanLost
qAdrszMessHumanWon:       .quad szMessHumanWon
qAdrszMessNewGame:        .quad szMessNewGame
qAdrszMessErrChoise:      .quad szMessErrChoise
qAdrsZoneConv:            .quad sZoneConv
/******************************************************************/
/*            string saisie                                       */
/******************************************************************/
/* x0 return the first character of human entry */
saisie:
    stp x1,lr,[sp,-16]!    // save  registers
    stp x2,x8,[sp,-16]!    // save  registers
    mov x0,#STDIN          // Linux input console
    ldr x1,qAdrsBuffer     // buffer address
    mov x2,#BUFFERSIZE     // buffer size
    mov x8,#READ           // request to read datas
    svc 0                  // call system
    ldr x1,qAdrsBuffer     // buffer address
    ldrb w0,[x1]           // load first character
100:
    ldp x2,x8,[sp],16      // restaur  2 registers
    ldp x1,lr,[sp],16      // restaur  2 registers
    ret                    // return to address lr x30

qAdrsBuffer:         .quad sBuffer
/***************************************************/
/*   Generation random number                  */
/***************************************************/
/* x0 contains limit  */
genereraleas:
    stp x1,lr,[sp,-16]!        // save  registers
    stp x2,x3,[sp,-16]!        // save  registers
    stp x4,x5,[sp,-16]!        // save  registers
    ldr x4,qAdrqGraine
    ldr x2,[x4]
    ldr x3,qNbDep1
    mul x2,x3,x2
    ldr x3,qNbDep2
    add x2,x2,x3
    str x2,[x4]                // maj de la graine pour l appel suivant
    cmp x0,#0
    beq 100f
    udiv x3,x2,x0
    msub x0,x3,x0,x2           // résult = remainder

100:                           // end function
    ldp x4,x5,[sp],16          // restaur  2 registers
    ldp x2,x3,[sp],16          // restaur  2 registers
    ldp x1,lr,[sp],16          // restaur  2 registers
    ret                        // return to address lr x30
/*****************************************************/
qAdrqGraine: .quad qGraine
qNbDep1:     .quad 0x0019660d
qNbDep2:     .quad 0x3c6ef35f

/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"


/* ARM assembly Raspberry PI  */
/*  program game21.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 HITTOTAL,   21
.equ BUFFERSIZE, 10

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessRules:         .ascii "21 Game\n"
                    .ascii "21 is a two player game, the game is played by choosing a number \n"
                    .ascii "(1, 2, or 3) to be added to the running total. The game is won by\n"
                    .ascii "the player whose chosen number causes the running total to reach \n"
                    .asciz "exactly 21. The running total starts at zero.\n\n\n"

szMessHumanChoice:  .asciz "Enter your choice (1,2, 3 or type (q)uit to exit): "
szMessErrChoise:    .asciz "invalid choice.\n "
szMessHumanBegin:   .asciz "The first move is human move.\n"
szMessPiBegin:      .asciz "The first move is Raspberry pi. \n"
szMessHumanWon:     .asciz "You won. \n"
szMessHumanLost:    .asciz "You lost. \n"
szMessTotal:        .asciz "The running total is @ \n"
szMessPiChoice:     .asciz "Raspberry choice if  @ \n"
szMessNewGame:      .asciz "New game (y/n) ? \n"
szCarriageReturn:   .asciz "\n"
.align 4
iGraine:  .int 123456
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:        .skip 24
sBuffer:          .skip BUFFERSIZE
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                 @ entry of program

    ldr r0,iAdrszMessRules
    bl affichageMess
1:
    mov r10,#0                         @ total = 0
    mov r0,#100
    bl genereraleas
    cmp r0,#50
    blt 2f
    ldr r0,iAdrszMessHumanBegin        @ human begin
    bl affichageMess
    b 4f
2:                                     @ Rasp begin
    ldr r0,iAdrszMessPiBegin
    bl affichageMess
    mov r0,#1
3:                                    @ rasp turn
    add r10,r10,r0
    ldr r1,iAdrsZoneConv
    bl conversion10                   @ call decimal conversion
    ldr r0,iAdrszMessPiChoice
    ldr r1,iAdrsZoneConv              @ insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess
    cmp r10,#HITTOTAL
    bne 4f
    ldr r0,iAdrszMessHumanLost
    bl affichageMess
    b 10f
4:                                    @ display current total
    mov r0,r10
    ldr r1,iAdrsZoneConv
    bl conversion10                   @ call decimal conversion
    ldr r0,iAdrszMessTotal
    ldr r1,iAdrsZoneConv              @ insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess

5:                                    @ human turn
    ldr r0,iAdrszMessHumanChoice
    bl affichageMess
    bl saisie
    cmp r0,#'q'                       @ quit ?
    beq 100f
    cmp r0,#'Q'
    beq 100f
    cmp r0,#'1'
    addeq r10,r10,#1
    beq 6f
    cmp r0,#'2'
    addeq r10,r10,#2
    beq 6f
    cmp r0,#'3'
    addeq r10,r10,#3
    beq 6f
    ldr r0,iAdrszMessErrChoise
    bl affichageMess
    b 5b
6:
    cmp r10,#HITTOTAL                @ total = maxi ?
    beq 9f                           @ yes -> human won
    cmp r10,#5                       @ else compute rasp number
    rsble r0,r10,#5
    ble 7f
    cmp r10,#9
    rsble r0,r10,#9
    ble 7f
    cmp r10,#13
    rsble r0,r10,#13
    ble 7f
    cmp r10,#17
    rsble r0,r10,#17
    ble 7f
    cmp r10,#21
    rsble r0,r10,#21
    ble 7f
7:                                  @ control number rasp
    cmp r0,#0
    ble 8f
    cmp r0,#3
    ble 3b
8:                                  @ if not ok, generate random number
    mov r0,#2
    bl genereraleas
    add r0,r0,#1
    b 3b                            @ and loop

9:                                  @ display human won
    ldr r0,iAdrszMessHumanWon
    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
iAdrszMessHumanBegin:     .int szMessHumanBegin
iAdrszMessPiBegin:        .int szMessPiBegin
iAdrszMessPiChoice:       .int szMessPiChoice
iAdrszMessTotal:          .int szMessTotal
iAdrszMessHumanChoice:    .int szMessHumanChoice
iAdrszMessHumanLost:      .int szMessHumanLost
iAdrszMessHumanWon:       .int szMessHumanWon
iAdrszMessNewGame:        .int szMessNewGame
iAdrszMessErrChoise:      .int szMessErrChoise
iAdrsZoneConv:            .int sZoneConv
/******************************************************************/
/*            string saisie                                       */
/******************************************************************/
/* 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
iAdrsBuffer:         .int sBuffer
/***************************************************/
/*   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,iNbDep1
    add r2,r2,r3
    str r2,[r4]                       @ maj de la graine pour l appel suivant
    cmp r0,#0
    beq 100f
    mov r1,r0                         @ 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"


print "-----------------------------"
print " Welcome to 21 Game"
print "-----------------------------"

players: ["A" "B"]
currentPlayer: sample players
nextPlayer: first players -- currentPlayer
runningTotal: new 0
num: 0

getNum: function [][
    result: strip input "Enter a number (1,2,3) / x to exit: "
    if result="x" -> exit
    return result
]

loop.forever @[currentPlayer nextPlayer] 'plays [
    print ["Running total:" runningTotal]
    print ["Player" plays "turn"]

    num: getNum

    while [or? [not? numeric? num][not? contains? 1..3 to :integer num]][
        num: getNum
    ]

    runningTotal: runningTotal + to :integer num

    print ""

    if runningTotal=21 [
        print ["Running total is 21. Player" plays "won!"]
        exit
    ]
]


Gui, font, S16
Gui, add, Radio, vRadioC , Cake
Gui, add, Radio, vRadioE x+0 Checked, Easy
Gui, add, Radio, vRadioH x+0, Hard
Gui, add, text, xs vT, Total : 00
Gui, add, text, xs vComputer, Computer Dealt 00
Gui, add, text, xs Section, Player 1
loop, 3
	Gui, add, button, x+5 vPlayer1_%A_Index% gTotal, % A_Index
Gui, add, button, xs vReset gReset, reset
Gui show,, 21 Game
Winners := [1,5,9,13,17,21]
gosub, reset
return
;-----------------------------------
reset:
total := 0
GuiControl,, T, % "Total : " SubStr("00" Total, -1)
GuiControl,, Computer, % "Computer Waiting"
Loop 3
	GuiControl, Enable, % "Player1_" A_Index
Random, rnd, 0, 1
if rnd
{
	Loop 3
		GuiControl, Disable, % "Player1_" A_Index
	gosub ComputerTurn
}
return
;-----------------------------------
Total:
Added := SubStr(A_GuiControl, 9,1)
Total += Added
GuiControl,, T, % "Total : " SubStr("00" Total, -1)
if (total >= 21)
{
	MsgBox % "Player 1 Wins"
	gosub reset
	return
}
Loop 3
	GuiControl, Disable, % "Player1_" A_Index
gosub, ComputerTurn
return
;-----------------------------------
ComputerTurn:
Gui, Submit, NoHide
Sleep 500
if RadioE
{
	if (total < 13)
		RadioC := true
	else
		RadioH := true
}
if RadioC
{
	Random, Deal, 1, 3
	total += Deal
}
if RadioH
{
	for i, v in Winners
		if (total >= v)
			continue
		else
		{
			Deal := v - total
			if Deal > 3
				Random, Deal, 1, 3
			total += Deal
			break
		}
}
GuiControl,, T, % "Total : " SubStr("00" Total, -1)
GuiControl,, Computer, % "Computer Dealt " Deal
if (total=21)
{
	MsgBox Computer Wins
	gosub, reset
}
else
	Loop 3
		GuiControl, Enable, % "Player1_" A_Index
return


#  Game 21 - an example in AWK language for Rosseta Code.

BEGIN {
    srand();
    GOAL = 21;
    best[0] = 1; best[1] = 1; best[2] = 3; best[3] = 2;

    print\
        "21 Game                                                          \n"\
        "                                                                 \n"\
        "21 is a two player game, the game is played by choosing a number \n"\
        "(1, 2, or 3) to be added to the running total. The game is won by\n"\
        "the player whose chosen number causes the running total to reach \n"\
        "exactly 21. The running total starts at zero.                    \n\n";

    newgame();
    prompt();

}

/[123]/ {
    move = strtonum($0);
    if (move + total <= GOAL) {
        update("human", strtonum($0));
        update("ai", best[total % 4]);
    }
    else
        invalid();
    prompt();
}
/[^123]/ {
    if ($0 == "quit") {
        print "goodbye";
        exit;
    }
    else {
        invalid();
        prompt();
    }
}

function prompt(){
    print "enter your choice (or type quit to exit): ";
}

function invalid(){
    print "invalid move";
}

function newgame() {
    print "\n---- NEW GAME ----\n";
    print "\nThe running total is currently zero.\n";
    total = 0;
    if (rand() < 0.5) {
        print "The first move is AI move.\n";
        update("ai", best[total % 4]);
    }
    else
        print "The first move is human move.\n";
}

function update(player, move) {
    printf "%8s:  %d = %d + %d\n\n", player, total + move, total, move;
    total += move;
    if (total == GOAL) {
        printf "The winner is %s.\n\n", player;
        newgame();
    }
}


shopt -s expand_aliases
alias bind_variables='
{
  local -ri goal_count=21
  local -ri player_human=0
  local -ri player_computer=1
  local -i turn=1
  local -i total_count=0
  local -i input_number=0
  local -i choose_turn=0
}
'
whose_turn() {
  case $(( ( turn + choose_turn ) % 2 )) in
   ${player_human}) echo "player";;
   ${player_computer}) echo "computer";;
  esac
}
next_turn() {
  let turn++
}
validate_number() {
  ! test ${input_number} -ge 1 -a ${input_number} -le $( max_guess )
}
prompt_number() {
  local prompt_str
  test $( max_guess ) -eq 1 && {
    prompt_str="enter the number 1 to win"
  true
  } || {
    prompt_str="enter a number between 1 and $( max_guess )"
  }
  while [ ! ]
  do
   read -p "${prompt_str} (or quit): "
   input_number=${REPLY}
   case ${REPLY} in
    "quit") {
      false
      return
    } ;;
   esac
   validate_number || break
   echo "try again"
  done
}
update_count() {
  let total_count+=input_number
}
remaining_count() {
  echo $(( goal_count - total_count ))
}
max_guess() {
  local -i remaining_count
  remaining_count=$( remaining_count )
  case $( remaining_count ) in
    1|2|3) echo ${remaining_count} ;;
    *) echo 3 ;;
  esac
}
iter() {
  update_count
  next_turn
}
on_game_over() {
  test ! ${input_number} -eq $( remaining_count ) || {
    test ! "$( whose_turn )" = "player" && {
      echo -ne "\nYou won!\n\n"
    true
    } || {
      echo -ne "\nThe computer won!\nGAME OVER\n\n"
    }
    false
  }
}
on_game_start() {
  echo 21 Game
  read -p "Press enter key to start"
}
choose_turn() {
  let choose_turn=${RANDOM}%2
}
choose_number() {
  local -i remaining_count
  remaining_count=$( remaining_count )
  case ${remaining_count} in
   1|2|3) {
     input_number=${remaining_count}
   } ;;
   5|6|7) {
     let input_number=remaining_count-4
   } ;;
   *) {
     let input_number=${RANDOM}%$(( $( max_guess ) - 1 ))+1
   }
  esac
}
game_play() {
  choose_turn
  while [ ! ]
  do
    echo "Total now ${total_count} (remaining: $( remaining_count ))"
    echo -ne "Turn: ${turn} ("
    test ! "$( whose_turn )" = "player" && {
      echo -n "Your"
    true
    } || {
      echo -n "Computer"
    }
    echo " turn)"
    test ! "$( whose_turn )" = "player" && {
      prompt_number || break
    true
    } || {
      choose_number
      sleep 2
      echo "Computer chose ${input_number}"
    }
    on_game_over || break
    sleep 1
    iter
  done
}
21_Game() {
  bind_variables
  on_game_start
  game_play
}
if [ ${#} -eq 0 ]
then
 true
else
 exit 1
fi
21_Game


/**
 * Game 21 - an example in C language for Rosseta Code.
 *
 * A simple game program whose rules are described below
 * - see DESCRIPTION string.
 *
 * This program should be compatible with C89 and up.
 */

/*
 * Turn off MS Visual Studio panic warnings which disable to use old gold
 * library functions like printf, scanf etc. This definition should be harmless
 * for non-MS compilers.
 */
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*
 * Define bool, true and false as needed. The stdbool.h is a standard header
 * in C99, therefore for older compilers we need DIY booleans. BTW, there is
 * no __STDC__VERSION__ predefined macro in MS Visual C, therefore we need
 * check also _MSC_VER.
 */
#if __STDC_VERSION__ >= 199901L || _MSC_VER >= 1800
#include <stdbool.h>
#else
#define bool int
#define true  1
#define false 0
#endif

#define GOAL               21
#define NUMBER_OF_PLAYERS   2
#define MIN_MOVE            1
#define MAX_MOVE            3
#define BUFFER_SIZE       256

#define _(STRING) STRING

/*
 * Spaces are meaningful: on some systems they can be visible.
 */
static char DESCRIPTION[] =
    "21 Game                                                          \n"
    "                                                                 \n"
    "21 is a two player game, the game is played by choosing a number \n"
    "(1, 2, or 3) to be added to the running total. The game is won by\n"
    "the player whose chosen number causes the running total to reach \n"
    "exactly 21. The running total starts at zero.                    \n\n";

static int total;

void update(char* player, int move)
{
    printf("%8s:  %d = %d + %d\n\n", player, total + move, total, move);
    total += move;
    if (total == GOAL)
        printf(_("The winner is %s.\n\n"), player);
}

int ai()
{
/*
 * There is a winning strategy for the first player. The second player can win
 * then and only then the frist player does not use the winning strategy.
 *
 * The winning strategy may be defined as best move for the given running total.
 * The running total is a number from 0 to GOAL. Therefore, for given GOAL, best
 * moves may be precomputed (and stored in a lookup table). Actually (when legal
 * moves are 1 or 2 or 3) the table may be truncated to four first elements.
 */
#if GOAL < 32 && MIN_MOVE == 1 && MAX_MOVE == 3
    static const int precomputed[] = { 1, 1, 3, 2, 1, 1, 3, 2, 1, 1, 3, 2, 1, 1,
        3, 2, 1, 1, 3, 2, 1, 1, 3, 2, 1, 1, 3, 2, 1, 1, 3 };
    update(_("ai"), precomputed[total]);
#elif MIN_MOVE == 1 && MAX_MOVE == 3
    static const int precomputed[] = { 1, 1, 3, 2};
    update(_("ai"), precomputed[total % (MAX_MOVE + 1)]);
#else
    int i;
    int move = 1;
    for (i = MIN_MOVE; i <= MAX_MOVE; i++)
        if ((total + i - 1) % (MAX_MOVE + 1) == 0)
            move = i;
    for (i = MIN_MOVE; i <= MAX_MOVE; i++)
        if (total + i == GOAL)
            move = i;
    update(_("ai"), move);
#endif
}

void human(void)
{
    char buffer[BUFFER_SIZE];
    int move;

    while ( printf(_("enter your move to play (or enter 0 to exit game): ")),
            fgets(buffer, BUFFER_SIZE, stdin),
            sscanf(buffer, "%d", &move) != 1 ||
            (move && (move < MIN_MOVE || move > MAX_MOVE || total+move > GOAL)))
        puts(_("\nYour answer is not a valid choice.\n"));
    putchar('\n');
    if (!move) exit(EXIT_SUCCESS);
    update(_("human"), move);
}

int main(int argc, char* argv[])
{
    srand(time(NULL));
    puts(_(DESCRIPTION));
    while (true)
    {
        puts(_("\n---- NEW GAME ----\n"));
        puts(_("\nThe running total is currently zero.\n"));
        total = 0;

        if (rand() % NUMBER_OF_PLAYERS)
        {
            puts(_("The first move is AI move.\n"));
            ai();
        }
        else
            puts(_("The first move is human move.\n"));

        while (total < GOAL)
        {
            human();
            ai();
        }
    }
}


/**
 *  Game 21 - an example in C++ language for Rosseta Code.
 *
 *  This version is an example of MVC architecture. It seems be a little cleaner
 *  than MVP. The friendship has broken encapsulations to avoid getters.
 */

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <limits>

using namespace std;
#define _(STR) STR

class Model
{
public:
    static const int GOAL = 21;
    static const int NUMBER_OF_PLAYERS = 2;
    static const int MIN_MOVE = 1;
    static const int MAX_MOVE = 3;
    int bestMove();
    bool update(const char* player, int move);
    bool isGameBegin();
    bool isGameOver();
protected:
    friend class View;
    View* view = nullptr;
    const char* player = nullptr;
    int oldTotal = 0;
    int newTotal = 0;
    int lastMove = 0;
};

class View
{
protected:
    Model* model;
public:
    View(Model* model);
    void init(const char* player);
    void update();
};

class Controller
{
protected:
    Model* model;
    View* view;
public:
    Controller(Model* model, View* view);
    int input();
    void clear();
    void run();
};

int Model::bestMove()
{
    // This is not the fastest algorithm. There is possible to precompute
    // and memorize all answers before game begin or even hard code them.

    int move = MIN_MOVE;
    for (int i = MIN_MOVE; i <= MAX_MOVE; i++)
        if ((newTotal + i - 1) % (MAX_MOVE + 1) == 0)
            move = i;
    for (int i = MIN_MOVE; i <= MAX_MOVE; i++)
        if (newTotal + i == GOAL)
            move = i;
    return move;
}

bool Model::update(const char* player, int move)
{
    if (move >= MIN_MOVE && move <= MAX_MOVE && newTotal + move <= GOAL)
    {
        this->player = player;
        oldTotal = newTotal;
        newTotal = oldTotal + move;
        lastMove = move;
        view->update();
        return true;
    }
    else
        return false;
}

bool Model::isGameBegin()
{
    return oldTotal == 0;
}

bool Model::isGameOver()
{
    return newTotal == GOAL;
}

View::View(Model* model)
{
    this->model = model;
    model->view = this;
}

void View::init(const char* player)
{
    if (model->newTotal == 0)
        cout << _("----NEW GAME----\n\n")
             << _("The running total is currently zero.\n")
             << _("The first move is ") << player << _(" move.\n\n");
}

void View::update()
{
    cout << setw(8) << model->player << ": " << model->newTotal << " = "
         << model->oldTotal << " + " << model->lastMove << endl << endl;
    if (model->isGameOver())
        cout << endl << _("The winner is ") << model->player << _(".\n\n\n");
}

Controller::Controller(Model* model, View* view)
{
    this->model = model;
    this->view = view;
}

void Controller::run()
{
    if (rand() % Model::NUMBER_OF_PLAYERS == 0)
    {
        view->init("AI");
        model->update("AI", model->bestMove());
    }
    else
        view->init("human");

    while (!model->isGameOver())
    {
        while (!model->update("human", input()))
            clear();
        model->update("AI", model->bestMove());
    }
}

int Controller::input()
{
    int value;
    cout << _("enter a valid number to play (or enter 0 to exit game): ");
    cin >> value;
    cout << endl;
    if (!cin.fail())
    {
        if (value == 0)
            exit(EXIT_SUCCESS);
        else
            return value;
    }
    else
        return model->MIN_MOVE - 1;
}

void Controller::clear()
{
    cout << _("Your answer is not a valid choice.") << endl;
    cin.clear();
    cin.ignore((streamsize)numeric_limits<int>::max, '\n');
}

int main(int argc, char* argv)
{
    srand(time(NULL));

    cout << _(
        "21 Game                                                          \n"
        "                                                                 \n"
        "21 is a two player game, the game is played by choosing a number \n"
        "(1, 2, or 3) to be added to the running total. The game is won by\n"
        "the player whose chosen number causes the running total to reach \n"
        "exactly 21. The running total starts at zero.                    \n\n");

    while (true)
    {
        Model* model = new Model();
        View* view = new View(model);
        Controller* controler = new  Controller(model, view);

        controler->run();

        delete controler;
        delete model;
        delete view;
    }
    return EXIT_SUCCESS; // dead code
}


// 21 Game

using System;

namespace _21Game
{
    public class Program
    {
        private const string computerPlayer = "Computer";
        private const string humanPlayer = "Player 1";

        public static string SwapPlayer(string currentPlayer)
        {
            if (currentPlayer == computerPlayer)
            {
                currentPlayer = humanPlayer;
            }
            else
            {
                currentPlayer = computerPlayer;
            }

            return currentPlayer;
        }

        public static void PlayGame()
        {
            bool playAnother = true;
            int total = 0;
            int final = 21;
            int roundChoice = 0;
            string currentPlayer = RandomPLayerSelect();
            int compWins = 0;
            int humanWins = 0;

            while (playAnother)
            {
                Console.WriteLine($"Now playing: {currentPlayer}");
                try
                {
                    if (currentPlayer == computerPlayer)
                    {
                       roundChoice =  CompMove(total);
                    }
                    else
                    {
                        roundChoice = int.Parse(Console.ReadLine());
                    }

                    if (roundChoice != 1 && roundChoice != 2 && roundChoice != 3)
                    {
                        throw new Exception();
                    }

                    total += roundChoice;
                }
                catch (Exception)
                {
                    Console.WriteLine("Invalid choice! Choose from numbers: 1, 2, 3.");
                    continue;
                }

                Console.WriteLine(total);

                if (total == final)
                {
                    if (currentPlayer == computerPlayer)
                    {
                        compWins++;
                    }
                    if (currentPlayer == humanPlayer)
                    {
                        humanWins++;
                    }
                    Console.WriteLine($"Winner: {currentPlayer}");
                    Console.WriteLine($"Comp wins: {compWins}. Human wins: {humanWins}");
                    Console.WriteLine($"do you wan to play another round? y/n");
                    var choice = Console.ReadLine();
                    if (choice == "y")
                    {
                        total = 0;
                    }
                    else if (choice == "n")
                    {
                        break;
                    }
                    else
                    {
                        Console.WriteLine("Invalid choice! Choose from y or n");
                        continue;
                    }
                }

                else if (total > 21)
                {
                    Console.WriteLine("Not the right time to play this game :)");
                    break;
                }

                currentPlayer = SwapPlayer(currentPlayer);
            }
        }

        public static bool CheckIfCanWin(int total)
        {
            bool result = false;
            if (total == 18)
            {
                result = true;
            }
            return result;
        }

        public static int CompMove(int total)
        {
            int choice = 0;

            if (CheckIfCanWin(total))
            {
                choice = 21 - total;
            }
            else
            {
                choice = new Random().Next(1,4);
            }

            return choice;
        }

        public static string RandomPLayerSelect()
        {
            string[] players = new string[] { computerPlayer, humanPlayer };
            var random = new Random().Next(0,2);
            return players[random];
        }

        public static void Main(string[] args)
        {
            // welcome message and rules
            Console.WriteLine("Welcome to 21 game \n");
            Console.WriteLine(@"21 is a two player game.
The game is played by choosing a number.
1, 2, or 3 to be added a total sum. \n
The game is won by the player reaches exactly 21. \n" );
            Console.WriteLine("Choose your number: (1, 2 or 3)");

            PlayGame();
        }
    }
}


1 rem 21 game
2 rem for rosetta code

3 rem initialization
4 l$=chr$(157):rem left cursor
5 dim p$(2),hc(2),ca(4):hc(1)=0:hc(2)=0:rem players
6 ca(0)=1:ca(1)=1:ca(2)=3:ca(3)=2:rem computer answers
7 dim cn$(6):for i=1 to 6:read cn$(i):next:rem computer names
8 def fn m(x)=(x-(int(x/4))*4):rem modulo function

10 rem optionally set screen colors here
20 print chr$(147);chr$(14):print spc(16);"21 GAME"
25 print:print " The goal of this game is to take turns"
26 print " adding the value of either 1, 2, or 3"
27 print " to a running total. The first player"
28 print " to bring the total to 21..."
29 print:print spc(10);"... WINS THE GAME!"
30 print:gosub 1000
35 print chr$(147):for p=1 to 2

40 rem game setup and get players
42 for p=1 to 2
44 print:print "Player";p;l$;", [H]uman or [C]omputer? ";
45 get k$:if k$<>"c" and k$<>"h" then 45
46 print k$:hc(p)=(k$="c")
50 print:print"Player";p;l$",":print"Enter your name";:if hc(p)then goto54
52 input p$(p):next p:goto 60
54 gosub 1500:print "? ";p$(p):next p
60 print:for p=1 to 2:print p;l$;". ";p$(p):next
65 print:print "Is this correct (y/n)? ";
70 get k$:if k$<>"y" and k$<>"n" then 70
75 print k$:if k$="n" then goto 35
80 print:print "Who will play first (1 or 2)? ";
85 get k$:if k$<"1" or k$>"2" then 85
90 fp=asc(k$)-48:print k$:print
95 print "Okay, ";p$(fp);" will play first.":print:gosub 1000

100 rem start main game loop
105 pi=fp:rt=0
110 print chr$(147);"Total so far:";rt
115 print:print p$(pi);"'s turn."
120 if hc(pi) then gosub 1200
125 if not hc(pi) then gosub 1100
130 rt=rt+ad
135 if rt=21 then goto 200
140 if rt>21 then print:print p$(pi);" loses by going over 21!!":goto 210
145 pi=pi+1:if pi>2 then pi=1
150 goto 110

200 rem winner winner chicken dinner
205 print:print "21! ";p$(pi);" wins the game!!!"
210 print:print "Would you like to play again? ";
215 get k$:if k$<>"n" and k$<>"y" then 215
220 print k$
225 if k$="n" then print:print "Okay, maybe another time. Bye!":end
230 goto 10

1000 rem pause for keypress
1010 z$=" Press a key to continue. "
1015 print spc(20-int(len(z$)/2));
1016 print chr$(18);z$;chr$(146)
1020 get k$:if k$="" then 1020
1025 return

1100 rem human player move
1105 print:print "How much to add,"
1110 print "1, 2, or 3 (0 to quit)";:input ad
1115 if ad<0 or ad>3 then print:print"Illegal amount. Try again.":goto1105
1120 if ad=0 then print:print "Game was ended by ";p$(pi);".":end
1125 return

1200 rem computer player move
1205 print:print "Thinking...";
1210 tt=int(rnd(1)*10)
1215 for t=1 to tt:print ".";:for i=1 to 250:next i,t:print
1220 rm=fn m(rt)
1225 ad=ca(rm)
1230 print:print p$(pi);" adds";ca(rm);l$;"."
1235 for t=1 to 1000:next t
1240 return

1500 rem pick a computer name
1505 pn=int(rnd(1)*6)+1:t$=cn$(pn)
1510 if t$=p$(p-1) then goto 1505
1515 p$(p)=t$
1520 return

2000 rem some computer names to pick from
2010 data "Commodore 64","VIC-20","Commodore 128","PET"
2020 data "Plus/4","Commodore 16"


print "Who reaches 21, wins"
print "Do you want to begin (y/n)"
if input = "n"
  who = 1
.
who$[] = [ "Human" "Computer" ]
repeat
  if who = 0
    repeat
      print ""
      print "Choose 1,2 or 3 (q for quit)"
      a$ = input
      n = number a$
      until a$ = "q" or (n >= 1 and n <= 3)
    .
  else
    sleep 1
    if sum mod 4 = 1
      n = random 3 + 1
    else
      n = 4 - (sum + 3) mod 4
    .
  .
  sum += n
  print who$[who] & ": " & n & " --> " & sum
  until sum >= 21 or a$ = "q"
  who = (who + 1) mod 2
.
if a$ <> "q"
  print ""
  if who = 0
    print "Congratulation, you won"
  else
    print "Sorry, you lost"
  .
.


USING: accessors combinators.random continuations formatting io
kernel math math.functions math.parser multiline qw random
sequences ;
IN: rosetta-code.21-game

STRING: welcome
21 is a two-player game. The game is played by choosing a number
(1, 2, or 3) to be added to the running total.

The game is won by the player whose chosen number causes the
running total to reach 21.

One player will be the computer. Players alternate supplying a
number to be added to the running total.
;

: .welcome ( -- ) welcome print ;

SYMBOLS: +computer+ +human+ ;

TUPLE: game total difficulty who ;

! Instead of saying something dry like 'invalid input,' spice
! it up a little.
: insult ( -- )
    {
        "No." "Er..." "Learn to read." "I think not."
        "Come on, is it really this difficult?"
    } random print ;

: get-input ( options-seq prompt-str -- str )
    dup "%s: " printf flush readln dup reach member?
    [ 2nip ] [ drop insult get-input ] if ;

: get-integer ( options-seq prompt-str -- n )
    get-input string>number ;

: get-difficulty ( -- x )
    qw{ 1 2 3 4 5 6 7 8 9 10 }
    "Difficulty (1-10)" get-integer 10 / ;

: human-move ( game -- n )
    drop qw{ q 1 2 3 } "Your move (1-3) or q to quit" get-input
    dup "q" = [ drop return ] when string>number ;

: choose-first-player ( difficulty -- player )
    [ +computer+ ] [ +human+ ] ifp ;

: <game> ( -- game )
    0 get-difficulty dup choose-first-player game boa ;

: swap-player ( game -- )
    [ +human+ = +computer+ +human+ ? ] change-who drop ;

: .total ( game -- ) total>> "Running total: %d\n" printf ;

: random-move ( game -- n ) drop 3 random 1 + ;

: boundary? ( n -- ? ) 1 - 4 divisor? ;

: (optimal-move) ( m -- n ) dup 4 / ceiling 4 * 1 + swap - ;

: optimal-move ( game -- n )
    total>> dup boundary? [ random-move ] [ (optimal-move) ] if ;

: computer-move ( game -- n )
    dup difficulty>> [ optimal-move ] [ random-move ] ifp
    dup "Computer chose %d.\n" printf ;

: do-turn ( game -- )
    dup dup who>> +human+ = [ human-move ] [ computer-move ] if
    [ + ] curry change-total dup .total swap-player ;

: do-turns ( game -- )
    [ dup total>> 20 > ] [ dup do-turn ] until
    dup swap-player who>> "%u wins!\n" printf ;

: play-21-game ( -- )
    .welcome nl [ <game> do-turns ] with-return ;

MAIN: play-21-game


type Player =
    | Computer
    | Person
type Play = {runningTotal:int; nextTurn:Player}
type Win =
    | ByExact of Player
    | ByOtherExceeded of Player
type Status =
    | Start
    | Playing of Play
    | Winner of Win
    | Exit

let rnd = System.Random ()
let randomFirstPlayer () =
    let selection = rnd.Next 2
    if selection = 0 then Computer else Person
let computerChose current =
    if current > 17 then 21-current // win strategy
    else if current > 13 && current < 17 then 17-current // naive thwart opponent strategy
    else rnd.Next(1, (min 4 (21-current+1)))

let (|Exact|Exceeded|Under|) i = if i = 21 then Exact else if i > 21 then Exceeded else Under
let (|ValidNumber|InvalidInput|Quit|) (s:string) =
    let trimmed = s.Trim().ToLower()
    if trimmed = "1" || trimmed = "2" || trimmed = "3" then ValidNumber
    else if trimmed = "q" then Quit
    else InvalidInput

let readable = function | Computer -> "Computer is" | Person -> "You are"

let rec looper = function
    | Start ->
        let firstPlayer = randomFirstPlayer ()
        printfn $"{readable firstPlayer} randomly selected to go first."
        looper (Playing {runningTotal=0; nextTurn=firstPlayer})
    | Playing play ->
        match play with
        | {runningTotal=Exact; nextTurn=Person} -> looper (Winner (ByExact Computer))
        | {runningTotal=Exact; nextTurn=Computer} -> looper (Winner (ByExact Person))
        | {runningTotal=Exceeded; nextTurn=player} -> looper (Winner (ByOtherExceeded player))
        | {runningTotal=r; nextTurn=player} ->
            match player with
            | Computer ->
                let computerChoice = computerChose r
                let total = r+computerChoice
                printfn $"Computer entered {computerChoice}. Current total now: {total}."
                looper (Playing {runningTotal=total; nextTurn=Person})
            | Person ->
                let input = printf "Enter number 1, 2, or 3 (or q to exit): "; System.Console.ReadLine ()
                match input with
                | ValidNumber ->
                    let playerChoice = System.Int32.Parse input
                    let total = r+playerChoice
                    printfn $"Player entered {playerChoice}. Current total now: {total}."
                    looper (Playing {runningTotal=total; nextTurn=Computer})
                | Quit -> looper Exit
                | InvalidInput -> printfn "Invalid input. Try again."; looper (Playing play)
    | Winner win ->
        match win with
        | ByExact player -> printfn $"{readable player} the winner by getting to 21."; looper Exit
        | ByOtherExceeded player -> printfn $"{readable player} the winner by not exceeding 21."; looper Exit
    | Exit -> printfn "Thanks for playing!"

let run () = looper Start


! game 21 - an example in modern fortran language for rosseta code.

subroutine ai
  common itotal, igoal
  if (itotal .lt. igoal) then
    move = 1
    do i = 1, 3
      if (mod(itotal + i - 1 , 4) .eq. 0) then
        move = i
      end if
    end do
    do i = 1, 3
      if (itotal + i .eq. igoal) then
        move = i
      end if
    end do
    print *, "      ai  ", itotal + move, " = ", itotal, " + ", move
    itotal = itotal + move
    if (itotal .eq. igoal) then
      print *, ""
      print *, "the winner is ai"
      print *, ""
    end if
  end if
end subroutine ai

subroutine human
  common itotal, igoal
  print *, ""
  do while (.true.)
    if (itotal + 1 .eq. igoal) then
      print *, "enter 1 (or 0 to exit): "
    else if (itotal + 2 .eq. igoal) then
      print *, "enter 1 or 2 (or 0 to exit): "
    else
      print *, "enter 1 or 2 or 3 (or 0 to exit)"
    end if
    read(*,*) move
    if (move .eq. 0) then
      stop
    else if (move .ge. 1 .and. move .le. 3 .and. move + itotal .le. igoal) then
      print *, "   human  ", itotal + move, " = ", itotal, " + ", move
      itotal = itotal + move
      if (itotal .eq. igoal) then
        print *, ""
        print *, "the winner is human"
        print *, ""
      end if
      return
    else
      print *, "a bad choice"
    end if
  end do
end subroutine human

program main
  common itotal, igoal
  print *,"game 21 - an example in fortran iv language for rosseta code."
  print *,""
  print *,"21 is a two player game, the game is played by choosing a number"
  print *,"(1, 2, or 3) to be added to the running total. the game is won"
  print *,"by the player whose chosen number causes the running total to reach"
  print *,"exactly 21. the running total starts at zero."
  print *,""
  i = irand(1)
  igoal = 21
  do while(.true.)
    print *, "---- new game ----"
    print *, ""
    print *, "the running total is currently zero."
    print *, ""
    itotal = 0
    if (mod(irand(0), 2) .eq. 0) then
      print *, "the first move is ai move."
      call ai
    else
      print *, "the first move is human move."
    end if
    print *, ""
    do while(itotal .lt. igoal)
      call human
      call ai
    end do
end do
end program main


#define PLAYER 1
#define COMP   0
randomize timer

dim as uinteger sum, add = 0
dim as uinteger turn = int(rnd+0.5)
dim as uinteger precomp(0 to 3) = { 1, 1, 3, 2 }

while sum < 21:
    turn = 1 - turn
    print using "The sum is ##"; sum
    if turn = PLAYER then
        print "It is your turn."
        while add < 1 orelse add > 3 orelse add+sum > 21
            input "How many would you like to add? ", add
        wend
    else
        print "It is the computer's turn."
        add = precomp(sum mod 4)
        print using "The computer adds #."; add
    end if
    print
    sum = sum + add
    add = 0
wend

if turn = PLAYER then
    print "Congratulations. You win."
else
    print "Bad luck. The computer wins."
end if


' Gambas module file

Private gameConunt As Integer = 0
Private numRound As Integer = 1
Private winPlayer As Integer = 0
Private winComputer As Integer = 0

Public Sub Main()

  Dim entra As String

  Print "Enter q to quit at any time\nThe computer will choose first"

  While gameConunt < 21
    Print "ROUND: " & numRound & "\n"
    gameConunt += selectCount(gameConunt)
    Print Subst("Running total is now &1 \n ", gameConunt)
    If gameConunt = 21 Then
      Inc winComputer
      Print "The computer has won !\n"
      endGame()
    Endif
    gameConunt += humanCount(gameConunt)
    Print Subst("Running total is now &1", gameConunt)
    If gameConunt = 21 Then
      Inc winPlayer
      Print "Congratulations! You've won!\n"
      endGame()
    Endif
    Inc numRound
  Wend

End

Private Function selectCount(cou As Integer) As Integer

  Dim a As Integer

  Randomize

  If cou < 18 Then
    a = Int(Rnd(1, 4))
  Else
    a = 21 - cou
  Endif

  Print "The computer choose " & a

  Return a

End

Private Function humanCount(cou As Integer) As Integer

  Dim entra As String
  Dim a As Integer

  While True
    Print "Your choice 1 to 3"
    Input entra
    If entra = "q" Then
      Print "Good Bye!"
      Quit
    Endif
    Try a = CInt(entra)
    If Error Then
      Print "Invalid entry, try again"
      Continue
    Endif
    If a < 1 Or a > 3 Then
      Print "Out of range, try again"
      Continue
    Endif
    If a + cou > 21 Then
      Print "The sum is greater than 21, try again"
      Continue
    Endif
    Return a
  Wend

End

Private Sub endGame()

  Dim entra As String

  Print Subst("Computer wins &1 games, human wins &2 games", winComputer, winPlayer)
  Print "\nPlay again? (y/n)"
  Input entra
  If entra = "y" Or entra = "Y" Then
    numRound = 1
    gameConunt = 0
    Print "Enter q to quit at any time\nThe computer will choose first"
  Else
    Print "Good Bye!"
    Quit
  Endif

End


package main

import (
    "bufio"
    "fmt"
    "log"
    "math/rand"
    "os"
    "strconv"
    "time"
)

var scanner = bufio.NewScanner(os.Stdin)

var (
    total = 0
    quit  = false
)

func itob(i int) bool {
    if i == 0 {
        return false
    }
    return true
}

func getChoice() {
    for {
        fmt.Print("Your choice 1 to 3 : ")
        scanner.Scan()
        if scerr := scanner.Err(); scerr != nil {
            log.Fatalln(scerr, "when choosing number")
        }
        text := scanner.Text()
        if text == "q" || text == "Q" {
            quit = true
            return
        }
        input, err := strconv.Atoi(text)
        if err != nil {
            fmt.Println("Invalid number, try again")
            continue
        }
        newTotal := total + input
        switch {
        case input < 1 || input > 3:
            fmt.Println("Out of range, try again")
        case newTotal > 21:
            fmt.Println("Too big, try again")
        default:
            total = newTotal
            fmt.Println("Running total is now", total)
            return
        }
    }
}

func main() {
    rand.Seed(time.Now().UnixNano())
    computer := itob(rand.Intn(2))
    fmt.Println("Enter q to quit at any time\n")
    if computer {
        fmt.Println("The computer will choose first")
    } else {
        fmt.Println("You will choose first")
    }
    fmt.Println("\nRunning total is now 0\n")
    var choice int
    for round := 1; ; round++ {
        fmt.Printf("ROUND %d:\n\n", round)
        for i := 0; i < 2; i++ {
            if computer {
                if total < 18 {
                    choice = 1 + rand.Intn(3)
                } else {
                    choice = 21 - total
                }
                total += choice
                fmt.Println("The computer chooses", choice)
                fmt.Println("Running total is now", total)
                if total == 21 {
                    fmt.Println("\nSo, commiserations, the computer has won!")
                    return
                }
            } else {
                getChoice()
                if quit {
                    fmt.Println("OK, quitting the game")
                    return
                }
                if total == 21 {
                    fmt.Println("\nSo, congratulations, you've won!")
                    return
                }
            }
            fmt.Println()
            computer = !computer
        }
    }
}


import System.Random
import System.IO
import System.Exit
import Control.Monad
import Text.Read
import Data.Maybe

promptAgain :: IO Int
promptAgain = do
  putStrLn "Invalid input - must be a number among 1,2 or 3. Try again."
  playerMove

playerMove :: IO Int
playerMove = do
  putStr "Your choice(1 to 3):"
  number <- getLine
  when (number == "q") $ do
    exitWith ExitSuccess
  let n = readMaybe number :: Maybe Int
  x <- if isNothing n
             then promptAgain
             else let val = read number
                   in if (val > 3 || val < 1)
                      then promptAgain
                      else return val
  return x

computerMove :: IO Int
computerMove = do
  x <- randomRIO (1, 3)
  putStrLn $ "Computer move:" ++ (show x)
  return x

gameLoop :: (IO Int, IO Int) -> IO Int
gameLoop moveorder = loop moveorder 0
  where loop moveorder total = do
        number <- fst moveorder
        let total1 = number + total
        putStrLn $ "Running total:" ++ (show total1)
        if total1 >= 21
           then return 0
           else do
             number <- snd moveorder
             let total2 = number + total1
             putStrLn $ "Running total:" ++ (show total2)
             if total2 >= 21
                then return 1
                else loop moveorder total2

main :: IO ()
main = do
  hSetBuffering stdout $ BlockBuffering $ Just 1
  putStrLn "Enter q to quit at any time"
  x <- randomRIO (0, 1) :: IO Int
  let (moveorder, names) = if x == 0
                 then ((playerMove, computerMove), ("Player", "Computer"))
                 else ((computerMove, playerMove), ("Computer", "Player"))
  when (x == 1) $ do
    putStrLn "Computer will start the game"
  y <- gameLoop moveorder
  when (y == 0) $ do
    putStrLn $ (fst names) ++ " has won the game"
  when (y == 1) $ do
    putStrLn $ (snd names) ++ " has won the game"


g21=: [email protected]@setup ::('g21: error termination'"_)

NB. non-verb must be defined before use, otherwise are assumed verbs.
Until=: 2 :'u^:(0-:v)^:_'

t=: 'score turn choice'
(t)=: i. # ;: t
empty erase't'

Fetch=: &{
Alter=: }

play=: move Until done
done=: 21 <: score Fetch
move=: [: update you`[email protected](turn Fetch)

update=: [email protected]@add
add=: score Alter~ (score Fetch + choice Fetch)
display=: [ ([: echo 'sum: {}' format~ score Fetch)
swap=: turn Alter~ ([: -. turn Fetch)

it=: ([ [: echo 'It chose {}.' format~ choice Fetch)@(choice Alter~ cb)
cb=: (1:`r`3:`2:)@.(4 | score Fetch)     NB. computer brain
r=: 3 :'>:?3'

you=: [email protected]@[email protected]
prompt=: [ ([: echo 'your choice?'"_)
acquire=: choice Alter~ ('123' i. 0 { ' ' ,~ read)
check=: (choice Alter~ (665 - score Fetch))@([ ([: echo 'g21: early termination'"_))^:(3 = choice Fetch)
qio1=: choice Alter~ ([: >: choice Fetch)

setup=: ([ [: echo 'On your turn enter 1 2 or 3, other entries exit'"_)@((3 :'?2') turn Alter ])@0 0 0"_  NB. choose first player randomly
summarize=: ' won' ,~  (];._2 'it you ') {~ turn Fetch

read=: 1!:1@:1:
write=: 1!:2 4: NB. unused
format=: ''&$: :([: ; (a: , [: ":&.> [) ,. '{}' ([ (E. <@}.;._1 ]) ,) ])


import java.util.Random;
import java.util.Scanner;

public class TwentyOneGame {

    public static void main(String[] args) {
        new TwentyOneGame().run(true, 21, new int[] {1, 2, 3});
    }

    public void run(boolean computerPlay, int max, int[] valid) {
        String comma = "";
        for ( int i = 0 ; i < valid.length ; i++ ) {
            comma += valid[i];
            if ( i < valid.length - 2 && valid.length >= 3 ) {
                comma += ", ";
            }
            if ( i == valid.length - 2 ) {
                comma += " or ";
            }
        }
        System.out.printf("The %d game.%nEach player chooses to add %s to a running total.%n" +
                "The player whose turn it is when the total reaches %d will win the game.%n" +
                "Winner of the game starts the next game.  Enter q to quit.%n%n", max, comma, max);
        int cGames = 0;
        int hGames = 0;
        boolean anotherGame = true;
        try (Scanner scanner = new Scanner(System.in);) {
            while ( anotherGame ) {
                Random r = new Random();
                int round = 0;
                int total = 0;
                System.out.printf("Start game %d%n", hGames + cGames + 1);
                DONE:
                    while ( true ) {
                        round++;
                        System.out.printf("ROUND %d:%n%n", round);
                        for ( int play = 0 ; play < 2 ; play++ ) {
                            if ( computerPlay ) {
                                int guess = 0;
                                //  try find one equal
                                for ( int test : valid ) {
                                    if ( total + test == max ) {
                                        guess = test;
                                        break;
                                    }
                                }
                                //  try find one greater than
                                if ( guess == 0 ) {
                                    for ( int test : valid ) {
                                        if ( total + test >= max ) {
                                            guess = test;
                                            break;
                                        }
                                    }
                                }
                                if ( guess == 0 ) {
                                    guess = valid[r.nextInt(valid.length)];
                                }
                                total += guess;
                                System.out.printf("The computer chooses %d%n", guess);
                                System.out.printf("Running total is now %d%n%n", total);
                                if ( total >= max ) {
                                    break DONE;
                                }
                            }
                            else {
                                while ( true ) {
                                    System.out.printf("Your choice among %s: ", comma);
                                    String line = scanner.nextLine();
                                    if ( line.matches("^[qQ].*") ) {
                                        System.out.printf("Computer wins %d game%s, human wins %d game%s.  One game incomplete.%nQuitting.%n", cGames, cGames == 1 ? "" : "s", hGames, hGames == 1 ? "" : "s");
                                        return;
                                    }
                                    try {
                                        int input = Integer.parseInt(line);
                                        boolean inputOk = false;
                                        for ( int test : valid ) {
                                            if ( input == test ) {
                                                inputOk = true;
                                                break;
                                            }
                                        }
                                        if ( inputOk ) {
                                            total += input;
                                            System.out.printf("Running total is now %d%n%n", total);
                                            if ( total >= max ) {
                                                break DONE;
                                            }
                                            break;
                                        }
                                        else {
                                            System.out.printf("Invalid input - must be a number among %s.  Try again.%n", comma);
                                        }
                                    }
                                    catch (NumberFormatException e) {
                                        System.out.printf("Invalid input - must be a number among %s.  Try again.%n", comma);
                                    }
                                }
                            }
                            computerPlay = !computerPlay;
                        }
                    }
                String win;
                if ( computerPlay ) {
                    win = "Computer wins!!";
                    cGames++;
                }
                else {
                    win = "You win and probably had help from another computer!!";
                    hGames++;
                }
                System.out.printf("%s%n", win);
                System.out.printf("Computer wins %d game%s, human wins %d game%s%n%n", cGames, cGames == 1 ? "" : "s", hGames, hGames == 1 ? "" : "s");
                while ( true ) {
                    System.out.printf("Another game (y/n)? ");
                    String line = scanner.nextLine();
                    if ( line.matches("^[yY]$") ) {
                        //  OK
                        System.out.printf("%n");
                        break;
                    }
                    else if ( line.matches("^[nN]$") ) {
                        anotherGame = false;
                        System.out.printf("Quitting.%n");
                        break;
                    }
                    else {
                        System.out.printf("Invalid input - must be a y or n.  Try again.%n");
                    }
                }
            }
        }
    }

}


<!DOCTYPE html>

    <meta charset="UTF-8">
    <meta name="keywords"    content="Game 21">
    <meta name="description" content="
      21 is a two player game, the game is played by choosing a number
      (1, 2, or 3) to be added to the running total. The game is won by
      the player whose chosen number causes the running total to reach
      exactly 21. The running total starts at zero.
    ">

    <meta name="dc.publisher" content="Rosseta Code">
    <meta name="dc.date"      content="2020-07-23">
    <meta name="dc.created"   content="2020-07-23">
    <meta name="dc.modified"  content="2020-07-30">
    <title>
        21 Game
    </title>

    <meta http-equiv="cache-control" content="no-cache">

    21 Game in ECMA Script (Java Script)

    21 is a two player game, the game is played by choosing a number
    (1, 2, or 3) to be added to the running total. The game is won by
    the player whose chosen number causes the running total to reach
    exactly 21. The running total starts at zero.

 Use buttons to play.

      human last choice:
      <input type="text" id="human" readonly>

      AI last choice:
      <input type="text" id="AI" readonly>

      running total:
      <input type="text" id="runningTotalText" readonly>

      <button onclick="choice(1);" id="choice1"> one   </button>
      <button onclick="choice(2);" id="choice2"> two   </button>
      <button onclick="choice(3);" id="choice3"> three </button>
      <button onclick="restart();"> restart </button>

    No script, no fun. Turn on Javascript on.


function trytowin(n)
    if 21 - n < 4
        println("Computer chooses $(21 - n) and wins. GG!")
        exit(0)
    end
end

function choosewisely(n)
    trytowin(n)
    targets = [1, 5, 9, 13, 17, 21]
    pos = findfirst(x -> x > n, targets)
    bestmove = targets[pos] - n
    if bestmove > 3
        println("Looks like I could lose. Choosing a 1, total now $(n + 1).")
        return n + 1
    end
    println("On a roll, choosing a $bestmove, total now $(n + bestmove).")
    n + bestmove
end

function choosefoolishly(n)
    trytowin(n)
    move = rand([1, 2, 3])
    println("Here goes, choosing $move, total now $(n + move).")
    n + move
end

function choosesemiwisely(n)
    trytowin(n)
    if rand() > 0.75
        choosefoolishly(n)
    else
        choosewisely(n)
    end
end

prompt(s) = (println(s, ": => "); return readline())

function playermove(n)
    rang = (n > 19) ? "1 is all" : ((n > 18) ? "1 or 2" : "1, 2 or 3")
    choice = 0
    while true
        nstr = prompt("Your choice ($rang), 0 to exit")
        if nstr == "0"
            exit(0)
        elseif nstr == "1"
            return n + 1
        elseif nstr == "2" && n < 20
            return n + 2
        elseif nstr == "3" && n < 19
            return n + 3
        end
    end
end

function play21game()
    n = 0
    level = prompt("Level of play (1=dumb, 3=smart)")
    algo = choosewisely
    if level == "1"
        algo = choosefoolishly
    elseif level == "2"
        algo = choosesemiwisely
    elseif level != "3"
        println("Bad choice syntax--default to smart choice")
    end
    whofirst = prompt("Does computer go first? (y or n)")
    if whofirst[1] == 'y' || whofirst[1] == 'Y'
        n = algo(n)
    end
    while n < 21
        n = playermove(n)
        if n == 21
            println("Player wins! Game over, gg!")
            break
        end
        n = algo(n)
    end
end

play21game()


gamewon = false
running_total = 0
player = 1
opponent = 2

while not gamewon do
  num = 0

  if player == 1 then
    opponent = 2
    repeat
      print("Enter a number between 1 and 3 (0 to quit):")
      num = io.read("*n")
      if num == 0 then
          os.exit()
      end
    until (num > 0) and (num <=3)
  end

  if player == 2 and not (gamewon) then
      opponent = 1
      if (21 - running_total <= 3) then
        num = 21 - running_total
      else
        num = math.random(1,3)
      end
      print("Player 2 picks number "..num)
  end

  running_total = running_total + num
  print("Total: "..running_total)

  if running_total == 21 then
    print("Player "..player.." wins!")
    gamewon = true
  end

  if running_total > 21 then
    print("Player "..player.." lost...")
    print("Player "..opponent.." wins!")
    gamewon = true
  end

  if player == 1 then
    player = 2
  else player = 1
  end

end


SeedRandom[1234];
ClearAll[ComputerChoose, HumanChoose]
ComputerChoose[n_] := If[n < 18, RandomChoice[{1, 2, 3}], 21 - n]
HumanChoose[] := ChoiceDialog["How many?", {1 -> 1, 2 -> 2, 3 -> 3, "Quit" -> -1}]
runningtotal = 0;
whofirst = ChoiceDialog["Who goes first?", {"You" -> 1, "Computer" -> 2}];
While[runningtotal < 21,
 If[whofirst == 1,
   choice = HumanChoose[];
   If[choice == -1, Break[]];
   Print["You choose = ", choice];
   runningtotal += choice;
   Print["Running total = ", runningtotal];
   If[runningtotal == 21, Print["You won!"]; Break[]];
   choice = ComputerChoose[runningtotal];
   Print["Computer choose = ", choice];
   runningtotal += choice;
   Print["Running total = ", runningtotal];
   If[runningtotal == 21, Print["Computer won!"]; Break[]];
   ,
   choice = ComputerChoose[runningtotal];
   Print["Computer choose = ", choice];
   runningtotal += choice;
   Print["Running total = ", runningtotal];
   If[runningtotal == 21, Print["Computer won!"]; Break[]];
   choice = HumanChoose[];
   If[choice == -1, Break[]];
   Print["You choose = ", choice];
   runningtotal += choice;
   Print["Running total = ", runningtotal];
   If[runningtotal == 21, Print["You won!"]; Break[]];
   ];
 ]


# 21 game.

import random
import strformat
import strutils

const
  Target = 21
  PossibleChoices: array[18..20, seq[string]] = [@["1", "2", "3"], @["1", "2"], @["1"]]
  Targets = [1, 5, 9, 13, 17, 21]     # Totals that a player must obtain to win.

#---------------------------------------------------------------------------------------------------

proc printTotal(total: int) =
  ## Print the running total.
  echo fmt"Running total is now {total}."

#---------------------------------------------------------------------------------------------------

proc computerPlays(total: var int) =
  ## Make the computer play.
  var choice: int
  if total in Targets:
    # No winning choice. Choose a random value.
    choice = rand(1..3)
  else:
    # Find the running total to get.
    for val in Targets:
      if val > total:
        choice = val - total
        break
  inc total, choice
  echo fmt"I choose {choice}."
  printTotal(total)

#---------------------------------------------------------------------------------------------------

proc prompt(message: string; answers: openArray[string]): int =
  ## Prompt a message and get an answer checking its validity against possible answers.

  while true:
    stdout.write(message & ' ')
    try:
      result = answers.find(stdin.readLine())
      if result >= 0:
        break
      echo fmt"Please answer one of: {answers.join("", "")}."
    except EOFError:
      echo ""
      return  # Quit.

#---------------------------------------------------------------------------------------------------

randomize()

echo "21 is a two player game. The game is played by choosing a number (1, 2, 3) to\n" &
     "be added to the running total. The game is won by the player whose chosen number\n" &
     "causes the running total to reach exactly 21. The running total starts at zero.\n"
echo "You can quit the game at any time by typing 'q'."

block mainLoop:

  while true:
    var total = 0

    # Choose the player who will play first.
    var answer = prompt("Who will play first ('you', 'me')?", ["q", "you", "me"])
    if answer == 0:
      echo "Quitting game."
      break
    elif answer == 1:
      computerPlays(total)

    # Internal game loop.
    while true:

      # Ask player its choice.
      let choices = if total > 18: PossibleChoices[total] else: PossibleChoices[18]
      let choice = prompt(fmt"Your choice ({choices.join("", "")})?", "q" & choices)
      if choice == 0:
        echo "Quitting game."
        break mainLoop

      # Update running total and check if player win.
      inc total, choice
      printTotal(total)
      if total == Target:
        echo "Congratulations, you win."
        break

      # Make computer play.
      computerPlays(total)
      if total == Target:
        echo "Sorry, I win."
        break

    # Ask player for another game.
    answer = prompt("Do you want to play another game (y, n)", ["q", "y", "n"])
    if answer != 1:
      echo "Quitting game."
      break


class TwentyOne {
  @quit : Bool;
  @player_total : Int;
  @computer_total : Int;

  function : Main(args : String[]) ~ Nil {
    TwentyOne->New()->Play();
  }

  New() {
  }

  method : Play() ~ Nil {
    player_first := Int->Random(1) = 1;

    "Enter 'q' to quit\n==="->PrintLine();
    do {
      if(player_first) {
        PlayerTurn();
        if(<>@quit) {
          "---"->PrintLine();
          ComputerTurn();
        };
      }
      else {
        ComputerTurn();
        "---"->PrintLine();
        PlayerTurn();
      };
      "==="->PrintLine();
    }
    while(<>@quit);
  }

  method : ComputerTurn() ~ Nil {
    input := Int->Random(1, 3);

    "Computer choose: {$input}"->PrintLine();
    @computer_total += input;

    if(@computer_total = 21) {
      "Computer Wins!"->PrintLine();
      @quit := true;
    }
    else if(@computer_total > 21) {
      "Computer Loses."->PrintLine();
      @quit := true;
    }
    else {
      "Computer total is {[email protected]_total}."->PrintLine();
    };
  }

  method : PlayerTurn() ~ Nil {
    input := GetInput();

    if(input = -1) {
      "Quit"->PrintLine();
      @quit := true;
    }
    else if(input = 0) {
      "Invalid Input!"->PrintLine();
    }
    else {
      @player_total += input;
    };

    if(@player_total = 21) {
      "Player Wins!"->PrintLine();
      @quit := true;
    }
    else if(@player_total > 21) {
      "Player Loses."->PrintLine();
      @quit := true;
    }
    else {
      "Player total is {[email protected]_total}."->PrintLine();
    };
  }

  function : GetInput() ~ Int {
    "Choosing a number beween 1-3: "->Print();

    input := System.IO.Console->ReadString();
    if(input->Size() = 1) {
      if(input->Get(0) = 'q') {
        return -1;
      };

      return input->ToInt();
    };

    return 0;
  }
}


program Game21;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.StrUtils, // for IfThen
  Winapi.Windows;  // for ClearScreen

const
  HARD_MODE = True;

var
  computerPlayer: string = 'Computer';
  humanPlayer: string = 'Player 1';

  // for change color
  ConOut: THandle;
  BufInfo: TConsoleScreenBufferInfo;

procedure ClearScreen;
var
  stdout: THandle;
  csbi: TConsoleScreenBufferInfo;
  ConsoleSize: DWORD;
  NumWritten: DWORD;
  Origin: TCoord;
begin
  stdout := GetStdHandle(STD_OUTPUT_HANDLE);
  Win32Check(stdout <> INVALID_HANDLE_VALUE);
  Win32Check(GetConsoleScreenBufferInfo(stdout, csbi));
  ConsoleSize := csbi.dwSize.X * csbi.dwSize.Y;
  Origin.X := 0;
  Origin.Y := 0;
  Win32Check(FillConsoleOutputCharacter(stdout, ' ', ConsoleSize, Origin, NumWritten));
  Win32Check(FillConsoleOutputAttribute(stdout, csbi.wAttributes, ConsoleSize,
    Origin, NumWritten));
  Win32Check(SetConsoleCursorPosition(stdout, Origin));
end;

procedure ResetColor;
begin
  SetConsoleTextAttribute(ConOut, BufInfo.wAttributes);
end;

procedure ChangeColor(color: Word);
begin
  ConOut := TTextRec(Output).Handle;
  GetConsoleScreenBufferInfo(ConOut, BufInfo);
  SetConsoleTextAttribute(TTextRec(Output).Handle, color);
end;

function SwapPlayer(currentPlayer: string): string;
begin
  Result := IfThen(currentPlayer = humanPlayer, computerPlayer, humanPlayer);
end;

function RandomPlayerSelect(): string;
begin
  Result := IfThen(Random() < 0.5, computerPlayer, humanPlayer);
end;

function CheckIfCanWin(total: Integer): Boolean;
begin
  result := (total >= 18);
end;

function CheckIfCanLose(total: Integer; var choose: Integer; hardMode: Boolean =
  False): Boolean;
var
  range: Integer;
begin
  range := 17 - total;
  Result := false;
  if (range > 0) and (range < 4) then
  begin
    Result := true;
    if hardMode then
      choose := range
    else
      choose := Random(range - 1) + 1;
  end;
end;

function CompMove(total: Integer): Integer;
begin
  if (CheckIfCanWin(total)) then
  begin
    exit(21 - total);
  end;

  if CheckIfCanLose(total, Result, HARD_MODE) then
    exit;

  Result := Random(3) + 1;
end;

function HumanMove: Integer;
var
  choice: string;
begin
  repeat
    Writeln('Choose from numbers: 1, 2, 3');
    Readln(choice);
  until TryStrToInt(choice, Result) and (Result in [1..3]);
end;

procedure PlayGame();
var
  playAnother: Boolean;
  total, final_, roundChoice, compWins, humanWins: Integer;
  choice, currentPlayer: string;
begin
  playAnother := True;
  total := 0;
  final_ := 21;
  roundChoice := 0;
  Randomize;
  currentPlayer := RandomPLayerSelect();
  compWins := 0;
  humanWins := 0;

  while (playAnother) do
  begin
    ClearScreen;
    ChangeColor(FOREGROUND_INTENSITY or FOREGROUND_GREEN);
    Writeln(total);
    ResetColor;
    Writeln('');

    Writeln('Now playing: ' + currentPlayer);
    if currentPlayer = computerPlayer then
      roundChoice := CompMove(total)
    else
      roundChoice := HumanMove;
    inc(total, roundChoice);

    if (total = final_) then
    begin
      if (currentPlayer = computerPlayer) then
      begin
        inc(compWins);
      end
      else
      begin
        inc(humanWins);
      end;

      ClearScreen;
      Writeln('Winner: ' + currentPlayer);
      Writeln('Comp wins: ', compWins, '. Human wins: ', humanWins, #10);
      Writeln('Do you wan to play another round? y/n');

      readln(choice);

      if choice = 'y' then
      begin
        total := 0;
        ClearScreen;
      end
      else if choice = 'n' then
        playAnother := false
      else
      begin
        Writeln('Invalid choice! Choose from y or n');
        Continue;
      end;
    end
    else if total > 21 then
    begin
      Writeln('Not the right time to play this game :)');
      break;
    end;

    currentPlayer := SwapPlayer(currentPlayer);
  end;

end;

const
  WELLCOME_MSG: array[0..5] of string = ('Welcome to 21 game'#10,
    '21 is a two player game.', 'The game is played by choosing a number.',
    '1, 2, or 3 to be added a total sum.'#10,
    'The game is won by the player reaches exactly 21.'#10, 'Press ENTER to start!'#10);

var
  i: Integer;

begin
  try
    for i := 0 to High(WELLCOME_MSG) do
      Writeln(WELLCOME_MSG[i]);
    ResetColor;
    Readln; // Wait press enter

    PlayGame();
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.


print <<'HERE';
The 21 game. Each player chooses to add 1, 2, or 3 to a running total.
The player whose turn it is when the total reaches 21 wins. Enter q to quit.
HERE

my $total = 0;

while () {
    print "Running total is: $total\n";
    my ($me,$comp);
    while () {
        print 'What number do you play> ';
        $me = <>; chomp $me;
        last if $me =~ /^[123]$/;
        insult($me);
    }
    $total += $me;
    win('Human') if $total >= 21;
    print "Computer plays: " . ($comp = 1+int(rand(3))) . "\n";
    $total += $comp;
    win('Computer') if $total >= 21;
}

sub win {
    my($player) = @_;
    print "$player wins.\n";
    exit;
}

sub insult {
    my($g) = @_;
    exit if $g =~ /q/i;
    my @insults = ('Yo mama', 'Jeez', 'Ummmm', 'Grow up');
    my $i = $insults[1+int rand($#insults)];
    print "$i, $g is not an integer between 1 and 3...\n"
}


--
-- demo\rosetta\21_Game.exw
-- ========================
--
with javascript_semantics -- DEV NORMALIZESIZE, CANFOCUS, "You" not checked, VALUE_HANDLE.
                          -- The radio_texts simply don't do anything at all in p2js.
constant title = "21 Game",
         help_text = """
Play by choosing 1, 2, or 3 to add to the running total (initially 0).

The first player to reach 21 wins.

If the computer goes first you cannot win.

If you leave your opponent on 18, 19, or 20, they will play {3,2,1} and win.
If you leave your opponent on 17, simply match their play {1,2,3} with {3,2,1} and win.
If you leave your opponent on 14, 15, or 16, they'll leave you on 17 and win.
So the aim is 21 (doh), and before that 17, 13, 9, 5, and 1. Anything else loses.
""",
         radio_texts = {"You","Computer","Random"},
         button_text = {"one","two","three","concede","new game","quit"}
integer total = 0

include pGUI.e
Ihandle dlg, vbox, frame, radios, playstate
sequence radioset, buttons

function show_help()
    IupMessage(title,help_text)
    return IUP_IGNORE -- (don't open browser help!)
end function

function play(integer n)
    if n!=0 then
        if n=6 then return IUP_CLOSE end if
        string title
        if n>3 then
            -- concede or new_game
            total = 0
            title = iff(n=4?"(conceded) ":"")
            title &= "Total is 0"
            Ihandle r = IupGetAttributePtr(radios,"VALUE_HANDLE")
            n = find(r,radioset)
            if n=2 or (n=3 and rand(2)=1) then
                title &= "," -- trigger a computer move
            end if
            IupSetInt(buttons[1..3],"ACTIVE",true)
        else
            -- n = 1..3
            title = sprintf("Total is %d",total)
            if total=21      -- (from key_cb)
            or total+n>21 then -- (invalid)
                return IUP_IGNORE
            end if
            total += n
            title &= sprintf(", you play %d (-> %d),",{n,total})
            if total=21 then title &= " you win" end if
        end if
        if find(',',title) and total!=21 then
            -- computer move
            sequence moves = {1,rand(3),3,2}
            n = moves[mod(total,4)+1]
            total += n
            title &= sprintf(" computer plays %d (-> %d)",{n,total})
            if total=21 then
                title &= ", computer wins"
            elsif mod(total,4)=1 then
                title &= ", (you've already lost)"
            end if
        end if
        if total=21 then
            title &= " GAME OVER"
            IupSetInt(buttons[1..4],"ACTIVE",false)
        else
            if total>18 then
                IupSetInt(buttons[22-total..3],"ACTIVE",false)
            end if
            IupSetInt(buttons[4],"ACTIVE",total!=0)
        end if
        IupSetFocus(dlg) -- (stops inactive button beeping)
        IupSetStrAttribute(playstate,"TITLE",title)
    end if
    return IUP_IGNORE
end function

function button_cb(Ihandle ih)
    string title = IupGetAttribute(ih,"TITLE")
    return play(find(title,button_text))
end function
constant cb_button = Icallback("button_cb")

function key_cb(Ihandle /*dlg*/, atom c)
    if c=K_ESC then return IUP_CLOSE end if -- (standard practice for me)
    if c=K_F5 then return IUP_DEFAULT end if -- (let browser reload work)
    if c=K_F1 then return show_help() end if
    return play(find(upper(c),"123CNQ"))
end function

IupOpen()
playstate = IupLabel("","EXPAND=HORIZONTAL, PADDING=10x10")
radioset = apply(true,IupToggle,{radio_texts,{"RIGHTBUTTON=YES, CANFOCUS=NO"}})
buttons = apply(true,IupButton,{button_text,cb_button,{"PADDING=5x5"}})
radios = IupRadio(IupHbox(radioset,"GAP=45"))
frame = IupHbox({IupLabel(`First Player:`),radios},"NORMALIZESIZE=VERTICAL")
vbox = IupVbox({frame,playstate,IupHbox(buttons,"GAP=10")},"MARGIN=20x10")
dlg = IupDialog(vbox,`TITLE="%s", MINSIZE=540x200`,{title})
IupShow(dlg)
IupSetCallback({dlg,buttons},"KEY_CB",Icallback("key_cb"))
IupSetAttributeHandle(NULL,"PARENTDIALOG",dlg)
{} = play(find("new game",button_text))
if platform()!=JS then
    IupMainLoop()
    IupClose()
end if


<!DOCTYPE html>

    <meta charset="UTF-8">
    <meta name="keywords"    content="Game 21">
    <meta name="description" content="
      21 is a two player game, the game is played by choosing a number
      (1, 2, or 3) to be added to the running total. The game is won by
      the player whose chosen number causes the running total to reach
      exactly 21. The running total starts at zero.
    ">

    <meta name="dc.publisher" content="Rosseta Code">
    <meta name="dc.date"      content="2020-07-31">
    <meta name="dc.created"   content="2020-07-31">
    <meta name="dc.modified"  content="2020-08-01">
    <title>
        21 Game
    </title>

    <meta http-equiv="cache-control" content="no-cache">

    21 Game in PHP 7

    21 is a two player game, the game is played by choosing a number
    (1, 2, or 3) to be added to the running total. The game is won by
    the player whose chosen number causes the running total to reach
    exactly 21. The running total starts at zero.

  <?php

    const GOAL = 21;
    const PLAYERS = array('AI', 'human');

    function best_move($n)
    {
      for ($i = 1; $i <= 3; $i++)
        if ($n + $i == GOAL)
          return $i;
      for ($i = 1; $i <= 3; $i++)
        if (($n + $i - 1) % 4 == 0)
          return $i;
      return 1;
    }

    if (isset($_GET['reset']) || !isset($_GET['total']))
    {
      $first = PLAYERS[rand(0, 1)];
      $total = 0;
      $human = 0;
      $ai = 0;
      $message = '';
      if ($first == 'AI')
      {
        $move = best_move($total);
        $ai = $move;
        $total = $total + $move;
      }
    }
    else
    {
      $first   = $_GET['first'];
      $total   = $_GET['total'];
      $human   = $_GET['human'];
      $ai      = $_GET['ai'];
      $message = $_GET['message'];
    }

    if (isset($_GET['move']))
    {
      $move = (int)$_GET['move'];
      $human = $move;
      $total = $total + $move;
      if ($total == GOAL)
        $message = 'The winner is human.';
      else
      {
        $move = best_move($total);
        $ai = $move;
        $total = $total + $move;
        if ($total == GOAL)
          $message = 'The winner is AI.';
      }
    }

    $state = array();
    for ($i = 1; $i <= 3; $i++)
      $state[$i] = $total + $i > GOAL ? 'disabled' : '';

    echo <<< END

        The first player is $first.
        Use buttons to play.

      <form class="ui">

          <input type='hidden' id='first' name='first' value='$first'>
          <input type='hidden' name='message' value='$message'>

          human last choice:
          <input type='text' name='human' readonly value='$human'>

          AI last choice:
          <input type='text' name='ai' readonly value='$ai'>

          running total:
          <input type='text' name='total' readonly value='$total'>

          <button type='submit' name='move' value='1' {$state[1]}> one   </button>
          <button type='submit' name='move' value='2' {$state[2]}> two   </button>
          <button type='submit' name='move' value='3' {$state[3]}> three </button>
          <button type='submit' name='reset' value='reset'> reset </button>

      </form>

        $message

    END
  ?>


import util.

main =>
    N = 0,
    Level = prompt("Level of play (1=dumb, 3=smart)"),
    Algo = choosewisely,
    if Level == "1" then
        Algo := choosefoolishly
    elseif Level == "2" then
        Algo := choosesemiwisely
    elseif Level != "3" then
        println("Bad choice syntax--default to smart choice")
    end,
    Whofirst = prompt("Does computer go first? (y or n)"),
    if Whofirst[1] == 'y' || Whofirst[1] == 'Y' then
        N := apply(Algo, N)
    end,
    while (N < 21)
        N := playermove(N),
        if N == 21 then
            println("Player wins! Game over, gg!"),
            halt
        end,
        N := apply(Algo,N)
    end.

trytowin(N) =>
    if 21 - N < 4 then
        printf("Computer chooses %w and wins. GG!\n", 21 - N),
        halt
    end.

choosewisely(N) = NextN =>
    trytowin(N),
    Targets = [1, 5, 9, 13, 17, 21],
    once ((member(Target, Targets), Target > N)),
    Bestmove = Target - N,
    if Bestmove > 3 then
        printf("Looks like I could lose. Choosing a 1, total now %w.\n", N + 1),
        NextN = N+1
    else
        printf("On a roll, choosing a %w, total now %w.\n", Bestmove, N + Bestmove),
        NextN = N + Bestmove
    end.

choosefoolishly(N) = NextN =>
    trytowin(N),
    Move = random() mod 3 + 1,
    printf("Here goes, choosing %w, total now %w.", Move, N+Move),
    NextN = N+Move.

choosesemiwisely(N) = NextN =>
    trytowin(N),
    if frand() > 0.75 then
        NextN = choosefoolishly(N)
    else
        NextN = choosewisely(N)
    end.

prompt(S) = Input =>
    printf(S ++ ": => "),
    Input = strip(read_line()).

playermove(N) = NextN =>
    Rang = cond(N > 19, "1 is all", cond(N > 18, "1 or 2", "1, 2 or 3")),
    Prompt = to_fstring("Your choice (%s), 0 to exit", Rang),
    Nstr = prompt(Prompt),
    if Nstr == "0" then
        halt
    elseif Nstr == "1" then
        NextN = N+1
    elseif Nstr == "2" && N < 20 then
        NextN = N + 2
    elseif Nstr == "3" && N < 19 then
        NextN = N + 3
    else
        NextN = playermove(N)
    end.


from random import randint
def start():
	game_count=0
	print("Enter q to quit at any time.\nThe computer will choose first.\nRunning total is now {}".format(game_count))
	roundno=1
	while game_count<21:
		print("\nROUND {}: \n".format(roundno))
		t = select_count(game_count)
		game_count = game_count+t
		print("Running total is now {}\n".format(game_count))
		if game_count>=21:
			print("So, commiserations, the computer has won!")
			return 0
		t = request_count()
		if not t:
			print('OK,quitting the game')
			return -1
		game_count = game_count+t
		print("Running total is now {}\n".format(game_count))
		if game_count>=21:
			print("So, congratulations, you've won!")
			return 1
		roundno+=1

def select_count(game_count):
	'''selects a random number if the game_count is less than 18. otherwise chooses the winning number'''
	if game_count<18:
		t= randint(1,3)
	else:
		t = 21-game_count
	print("The computer chooses {}".format(t))
	return t

def request_count():
	'''request user input between 1,2 and 3. It will continue till either quit(q) or one of those numbers is requested.'''
	t=""
	while True:
		try:
			t = raw_input('Your choice 1 to 3 :')
			if int(t) in [1,2,3]:
				return int(t)
			else:
				print("Out of range, try again")
		except:
			if t=="q":
				return None
			else:
				print("Invalid Entry, try again")

c=0
m=0
r=True
while r:
	o = start()
	if o==-1:
		break
	else:
		c+=1 if o==0 else 0
		m+=1 if o==1 else 0
	print("Computer wins {0} game, human wins {1} games".format(c,m))
	t = raw_input("Another game?(press y to continue):")
	r = (t=="y")


  [ say
    "Who goes first: Computer, Player"
    say " or Random?"  cr
    [ $ "Enter C, P or R: " input
      dup size 1 != iff drop again
      0 peek
      dup char C = iff [ drop 0 ] done
      dup char P = iff [ drop 1 ] done
      char R = iff [ 2 random ] done
       again ]
    cr
    dup iff [ say "You go first." ]
    else [ say "I will go first." ]
    cr ]                                  is chooseplayer (   --> n   )

                                  forward is player       ( n --> n x )

  [ [ dup 17 > iff 1 done
      4 over 4 mod
      dup 0 = if [ drop 3 ]
      - ]
    dup say "Computer chooses " echo
    say "." cr
    + ' player ]                          is computer     ( n --> n x )

  [ say "Choose 1 2 or 3 (running "
    $ "total must not exceed 21, Q to quit): " input
    dup $ "Q" = iff [ drop 21 999 ] done
    trim reverse trim reverse
    $->n not iff drop again
    dup 1 4 within not iff drop again
    2dup + 21 > iff drop again
    + ' computer ]                  resolves player       ( n --> n x )

  [ say "The player who makes 21 loses." cr
    0 chooseplayer
    iff [ ' player ] else [ ' computer ]
    [ say "Running total is "
      over echo say "." cr cr
      do
      over 21 = until ]
    cr
    dup 999 = iff
      [ drop 2drop say "Quitter!" ] done
    ' computer = iff
        [ say "The computer won!" ]
    else [ say "You won! Well done!" ]
    drop ]                                 is play        (   -->     )