June 2018 Update

This commit is contained in:
Ingy döt Net 2018-06-22 20:57:24 +00:00
parent ba8067c3b7
commit 22f33d4004
5278 changed files with 84726 additions and 14379 deletions

View file

@ -1,9 +1,12 @@
[[File:Tic_tac_toe.jpg|500px||right]]
;Task:
Play a game of [[wp:Tic-tac-toe|tic-tac-toe]]. Ensure that legal moves are played and that a winning position is notified.
Play a game of [[wp:Tic-tac-toe|tic-tac-toe]].
Ensure that legal moves are played and that a winning position is notified.
;See also
* [http://mathworld.wolfram.com/Tic-Tac-Toe.html Mathworld™, Tic-Tac-Toe game].
*   [http://mathworld.wolfram.com/Tic-Tac-Toe.html MathWorld™, Tic-Tac-Toe game].
*   [https://en.wikipedia.org/wiki/Tic-tac-toe Wikipedia tic-tac-toe].
<br><br>

View file

@ -0,0 +1,99 @@
! This is a fortran95 implementation of the game of tic-tac-toe.
! - Objective was to use less than 100 lines.
! - No attention has been devoted to efficiency.
! - Indentation by findent: https://sourceforge.net/projects/findent/
! - This is free software, use as you like at own risk.
! - Compile: gfortran -o tictactoe tictactoe.f90
! - Run: ./tictactoe
! Comments to: wvermin at gmail dot com
module tic
implicit none
integer :: b(9)
contains
logical function iswin(p)
integer,intent(in) :: p
iswin = &
all(b([1,2,3])==p).or.all(b([4,5,6])==p).or.all(b([7,8,9])==p).or.&
all(b([1,4,7])==p).or.all(b([2,5,8])==p).or.all(b([3,6,9])==p).or.&
all(b([1,5,9])==p).or.all(b([3,5,7])==p)
end function iswin
subroutine printb(mes)
character(len=*) :: mes
integer :: i,j
character :: s(0:2) = ['.','X','O']
print "(3a3,' ',3i3)",(s(b(3*i+1:3*i+3)),(j,j=3*i+1,3*i+3),i=0,2)
if(mes /= ' ') print "(/,a)",mes
end subroutine printb
integer recursive function minmax(player,bestm) result(bestv)
integer :: player,bestm,move,v,bm,win=1000,inf=100000
real :: x
if (all(b .ne. 0)) then
bestv = 0
else
bestv = -inf
do move=1,9
if (b(move) == 0) then
b(move) = player
if (iswin(player)) then
v = win
else
call random_number(x)
v = -minmax(3-player,bm) - int(10*x)
endif
if (v > bestv) then
bestv = v
bestm = move
endif
b(move) = 0
if (v == win) exit
endif
enddo
endif
end function minmax
end module tic
program tictactoe
! computer: player=1, user: player=2
use tic
implicit none
integer :: move,ios,v,bestmove,ply,player=2,k,values(8)
integer,allocatable :: seed(:)
call date_and_time(values=values)
call random_seed(size=k)
allocate(seed(k))
seed = values(8)+1000*values(7)+60*1000*values(6)+60*60*1000*values(5)
call random_seed(put=seed)
mainloop: do
b = 0
call printb('You have O, I have X. You enter 0: game ends.')
plyloop: do ply=0,4
if (player == 2 .or. ply >0 ) then ! user move
write(*,"(/,a)",advance='no'),'Your move? (0..9) '
getloop: do
readloop: do
read (*,*,iostat=ios),move
if (ios == 0 .and. move >= 0 .and. move <= 9) exit readloop
write(*,"(a)",advance='no'),'huh? Try again (0..9): '
enddo readloop
if ( move == 0) exit mainloop
if (b(move) == 0) exit getloop
write(*,"(a)",advance='no'),'Already occupied, again (0..9): '
enddo getloop
b(move) = 2
if(iswin(2)) then ! this should not happen
call printb('***** You win *****')
exit plyloop
endif
endif
v = minmax(1,bestmove) ! computer move
b(bestmove) = 1
if(iswin(1)) then
call printb('***** I win *****')
exit plyloop
endif
write(*,"(/,a,i3)"), 'My move: ',bestmove
call printb(' ')
enddo plyloop
if(ply == 5) write(*,"('***** Draw *****',/)")
player = 3-player
enddo mainloop
end program

View file

@ -0,0 +1,107 @@
// version 1.1.51
import java.util.Random
val r = Random()
val b = Array(3) { IntArray(3) } // board -> 0: blank; -1: computer; 1: human
var bestI = 0
var bestJ = 0
fun checkWinner(): Int {
for (i in 0..2) {
if (b[i][0] != 0 && b[i][1] == b[i][0] && b[i][2] == b[i][0]) return b[i][0]
if (b[0][i] != 0 && b[1][i] == b[0][i] && b[2][i] == b[0][i]) return b[0][i]
}
if (b[1][1] == 0) return 0
if (b[1][1] == b[0][0] && b[2][2] == b[0][0]) return b[0][0]
if (b[1][1] == b[2][0] && b[0][2] == b[1][1]) return b[1][1]
return 0
}
fun showBoard() {
val t = "X O"
for (i in 0..2) {
for (j in 0..2) print("${t[b[i][j] + 1]} ")
println()
}
println("-----")
}
fun testMove(value: Int, depth: Int): Int {
var best = -1
var changed = 0
var score = checkWinner()
if (score != 0) return if (score == value) 1 else -1
for (i in 0..2) {
for (j in 0..2) {
if (b[i][j] != 0) continue
b[i][j] = value
changed = value
score = -testMove(-value, depth + 1)
b[i][j] = 0
if (score <= best) continue
if (depth == 0) {
bestI = i
bestJ = j
}
best = score
}
}
return if (changed != 0) best else 0
}
fun game(user: Boolean): String {
var u = user
for (i in 0..2) b[i].fill(0)
print("Board postions are numbered so:\n1 2 3\n4 5 6\n7 8 9\n")
print("You have O, I have X.\n\n")
for (k in 0..8) {
while (u) {
var move: Int?
do {
print("Your move: ")
move = readLine()!!.toIntOrNull()
}
while (move != null && move !in 1..9)
move = move!! - 1
val i = move / 3
val j = move % 3
if (b[i][j] != 0) continue
b[i][j] = 1
break
}
if (!u) {
if (k == 0) { // randomize if computer opens, less boring
bestI = r.nextInt(Int.MAX_VALUE) % 3
bestJ = r.nextInt(Int.MAX_VALUE) % 3
}
else testMove(-1, 0)
b[bestI][bestJ] = -1
val myMove = bestI * 3 + bestJ + 1
println("My move: $myMove")
}
showBoard()
val win = checkWinner()
if (win != 0) return (if (win == 1) "You win" else "I win") + ".\n\n"
u = !u
}
return "A draw.\n\n"
}
fun main(args: Array<String>) {
var user = false
while (true) {
user = !user
print(game(user))
var yn: String
do {
print("Play again y/n: ")
yn = readLine()!!.toLowerCase()
}
while (yn != "y" && yn != "n")
if (yn != "y") return
println()
}
}

View file

@ -0,0 +1,237 @@
global $ -- object representing simple framework
global gBoard -- current board image
global gBoardTemplate -- empty board image
global gHumanChip -- cross image
global gComputerChip -- circle image
global gM -- 3x3 matrix storing game state: 0=free cell, 1=human cell, -1=computer cell
global gStep -- index of current move (1..9)
global gGameOverFlag -- TRUE if current game is over
----------------------------------------
-- Entry point
----------------------------------------
on startMovie
-- libs
$.import("sprite")
-- window properties
_movie.stage.title = "Tic-Tac-Toe"
_movie.stage.rect = rect(0, 0, 224, 310)
_movie.centerStage = TRUE
-- load images from filesystem
m = new(#bitmap)
m.importFileInto($.@("resources/cross.bmp"), [#trimWhiteSpace:FALSE])
gHumanChip = m.image
m = new(#bitmap)
m.importFileInto($.@("resources/circle.bmp"), [#trimWhiteSpace:FALSE])
gComputerChip = m.image
-- create GUI
m = new(#bitmap)
m.importFileInto($.@("resources/board.bmp"))
m.regpoint = point(0, 0)
s = $.sprite.make(m, [#loc:point(20, 20)], TRUE)
s.addListener(#mouseDown, _movie, #humanMove)
gBoard = m.image
gBoardTemplate = gBoard.duplicate()
m = $.sprite.newMember(#button, [#text:"New Game (Human starts)", #fontstyle:"bold", #rect:rect(0, 0, 180, 0)])
s = $.sprite.make(m, [#loc:point(20, 220)], TRUE)
s.addListener(#mouseDown, _movie, #newGame, 1)
m = $.sprite.newMember(#button, [#text:"New Game (Computer starts)", #fontstyle:"bold", #rect:rect(0, 0, 180, 0)])
s = $.sprite.make(m, [#loc:point(20, 250)], TRUE)
s.addListener(#mouseDown, _movie, #newGame, -1)
m = $.sprite.newMember(#field, [#name:"feedback", #editable:FALSE, #fontstyle:"bold", #alignment:"center",\
#border:0, #color:rgb(255, 0, 0), #rect:rect(0, 0, 180, 0)])
s = $.sprite.make(m, [#loc:point(20, 280)], TRUE)
newGame(1)
-- show the application window
_movie.updateStage()
_movie.stage.visible = TRUE
end
----------------------------------------
-- Starts a new game
----------------------------------------
on newGame (whoStarts)
-- reset board
gBoard.copyPixels(gBoardTemplate, gBoardTemplate.rect, gBoardTemplate.rect)
-- clear feedback
member("feedback").text = ""
-- reset states
gM = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
gStep = 0
gGameOverFlag = FALSE
if whoStarts=-1 then computerMove()
end
----------------------------------------
-- Handles a human move (mouse click)
----------------------------------------
on humanMove ()
if gGameOverFlag then return
-- find cell for mouse position
p = _mouse.clickLoc - sprite(1).loc
if p.locH mod 60<4 or p.locV mod 60<4 then return
p = p / 60
x = p[1] + 1
y = p[2] + 1
if gM[x][y] then return -- ignore illegal moves
gM[x][y] = 1
-- update cell image
p = p * 60
gBoard.copyPixels(gHumanChip, gHumanChip.rect.offset(4+p[1], 4+p[2]), gHumanChip.rect)
-- proceed (unless game over)
gStep = gStep + 1
if not checkHumanMove(x, y) then computerMove()
end
----------------------------------------
-- Checks if human has won or game ended with draw
----------------------------------------
on checkHumanMove (x, y)
if sum([gM[x][1], gM[x][2], gM[x][3]])=3 then return gameOver(1, [[x, 1], [x, 2], [x, 3]])
if sum([gM[1][y], gM[2][y], gM[3][y]])=3 then return gameOver(1, [[1, y], [2, y], [3, y]])
if x=y and sum([gM[1][1], gM[2][2], gM[3][3]])=3 then return gameOver(1, [[1, 1], [2, 2], [3, 3]])
if x+y=4 and sum([gM[1][3], gM[2][2], gM[3][1]])=3 then return gameOver(1, [[1, 3], [2, 2], [3, 1]])
if gStep=9 then return gameOver(0)
return FALSE
end
----------------------------------------
-- Checks if selecting specified empty cell makes computer or human win
----------------------------------------
on checkCellWins (x, y, who)
wins = who*2
if sum([gM[1][y], gM[2][y], gM[3][y]]) = wins then return [[1, y], [2, y], [3, y]]
if sum([gM[x][1], gM[x][2], gM[x][3]]) = wins then return [[x, 1], [x, 2], [x, 3]]
if x=y and sum([gM[1][1], gM[2][2], gM[3][3]]) = wins then return [[1, 1], [2, 2], [3, 3]]
if x+y=4 and sum([gM[1][3], gM[2][2], gM[3][1]]) = wins then return [[1, 3], [2, 2], [3, 1]]
return FALSE
end
----------------------------------------
-- Handles game over
----------------------------------------
on gameOver (winner, cells)
gGameOverFlag = TRUE
if winner = 0 then
member("feedback").text = "It's a draw!"
else
-- hilite winning line with yellow
img = image(56, 56, 32)
img.fill(img.rect, rgb(255, 255, 0))
repeat with c in cells
x = (c[1]-1)*60 + 4
y = (c[2]-1)*60 + 4
gBoard.copyPixels(img, img.rect.offset(x, y), img.rect, [#ink:#darkest])
end repeat
member("feedback").text = ["Human", "Computer"][1+(winner=-1)] & " has won!"
end if
return TRUE
end
----------------------------------------
-- Calculates next computer move
----------------------------------------
on computerMove ()
gStep = gStep + 1
-- move 1: select center
if gStep=1 then return doComputerMove(2, 2)
-- move 2 (human started)
if gStep=2 then
if gM[2][2]=1 then
-- if center, select arbitrary corner
return doComputerMove(1, 1)
else
-- otherwise select center
return doComputerMove(2, 2)
end if
end if
-- move 3 (computer started)
if gStep=3 then
-- if corner, select diagonally opposite corner
if gM[1][1]=1 then return doComputerMove(3, 3)
if gM[3][3]=1 then return doComputerMove(1, 1)
if gM[1][3]=1 then return doComputerMove(3, 1)
return doComputerMove(1, 1) -- top left corner as default
end if
-- get free cells
free = []
repeat with x = 1 to 3
repeat with y = 1 to 3
if gM[x][y]=0 then free.add([x, y])
end repeat
end repeat
-- check if computer can win now
repeat with c in free
res = checkCellWins(c[1], c[2], -1)
if res<>FALSE then
doComputerMove(c[1], c[2])
return gameOver(-1, res)
end if
end repeat
-- check if human could win with next move (if yes, prevent it)
repeat with c in free
res = checkCellWins(c[1], c[2], 1)
if res<>FALSE then return doComputerMove(c[1], c[2], TRUE)
end repeat
-- move 4 (human started): prevent "double mills"
if gStep=4 then
if gM[2][2]=1 and (gM[1][1]=1 or gM[3][3]=1) then return doComputerMove(3, 1)
if gM[2][2]=1 and (gM[1][3]=1 or gM[3][1]=1) then return doComputerMove(1, 1)
if gM[2][3]+gM[3][2]=2 then return doComputerMove(3, 3)
if gM[1][2]+gM[2][3]=2 then return doComputerMove(1, 3)
if gM[1][2]+gM[2][1]=2 then return doComputerMove(1, 1)
if gM[2][1]+gM[3][2]=2 then return doComputerMove(3, 1)
if (gM[1][3]+gM[3][1]=2) or (gM[1][1]+gM[3][3]=2) then return doComputerMove(2, 1)
end if
-- move 5 (computer started): try to create a "double mill"
if gStep=5 then
repeat with x = 1 to 3
col = [gM[x][1], gM[x][2], gM[x][3]]
if not (sum(col)=-1 and max(col)=0) then next repeat
repeat with y = 1 to 3
row = [gM[1][y], gM[2][y], gM[3][y]]
if not (sum(row)=-1 and max(row)=0 and gM[x][y]=0) then next repeat
return doComputerMove(x, y)
end repeat
end repeat
end if
-- otherwise use first free cell
c = free[1]
doComputerMove(c[1], c[2])
end
----------------------------------------
-- Updates state matrix and cell image
----------------------------------------
on doComputerMove (x, y, checkDraw)
gM[x][y] = -1
gBoard.copyPixels(gComputerChip, gComputerChip.rect.offset(4+(x-1)*60, 4+(y-1)*60), gComputerChip.rect)
if checkDraw and gStep=9 then gameOver(0)
end
----------------------------------------
--
----------------------------------------
on sum (aLine)
return aLine[1]+aLine[2]+aLine[3]
end

View file

@ -1,12 +1,10 @@
use v6;
my @board = 1..9;
my @winning-positions = [0..2], [3..5], [6..8], [0,3,6], [1,4,7], [2,5,8],
[0,4,8], [6,4,2];
sub get-winner() {
for @winning-positions {
return (@board[$_][0], $_) if [eq] @board[$_];
return (@board[|$_][0], $_) if [eq] @board[|$_];
}
}
@ -22,12 +20,13 @@ sub ai-move() {
}
sub print-board() {
say @board.map({ "$^a | $^b | $^c" }).join("\n--+---+--\n"), "\n";
print "\e[2J";
say @board.map({ "$^a | $^b | $^c" }).join("\n--+---+--\n"), "\n";
}
sub human-move() {
my $pos = prompt "Choose one of { (free-indexes >>+>> 1).join(",") }: ";
if $pos eq any(free-indexes >>+>> 1) {
my $pos = prompt "Choose one of { (free-indexes() »+» 1).join(",") }: ";
if $pos eq any(free-indexes() »+» 1) {
@board[$pos - 1] = 'x';
} else {
say "Sorry, you want to put your 'x' where?";
@ -35,14 +34,14 @@ sub human-move() {
}
}
for (&ai-move, &human-move) xx * {
for flat (&ai-move, &human-move) xx * {
print-board;
.();
last if get-winner() or not free-indexes;
last if get-winner() or not free-indexes;
.();
}
if get-winner() -> ($player, $across) {
say "$player wins across [", ($across >>+>> 1).join(", "), "].";
say "$player wins across [", ($across »+» 1).join(", "), "].";
} else {
say "How boring, a draw!";
}

View file

@ -1,111 +1,143 @@
/*REXX program plays (with a human) the tic─tac─toe game on an NxN grid. */
$=copies('', 9) /*eyecatcher literal for error messages*/
oops =$ '***error*** '; cell@ ="cell number" /*a couple of literals for some SAYs. */
sing=''; jam=""; bar=''; junc=""; dbl=jam || bar || junc
sw=linesize() - 1 /*obtain width of the terminal (less 1)*/
$=copies('', 9) /*eyecatcher for error messages, prompt*/
oops = $ '***error*** ' /*literal for when an error happens. */
single = ''; jam= ""; bar= ''; junc= ""; dbl=jam || bar || junc
sw = linesize() - 1 /*obtain width of the terminal (less 1)*/
parse arg N hm cm .,@. /*obtain optional arguments from the CL*/
if N=='' | N=="," then N=3; oN=N /*N not specified? Then use default.*/
N=abs(N); NN=N*N; middle=NN%2+N%2 /*if N < 0, then computer goes first. */
if N<2 then do; say oops 'tictactoe grid is too small: ' N; exit; end
pad=left('', sw%NN) /*display padding: 6x6 in 80 columns.*/
if hm=='' then hm="X"; if cm=='' then cm="O" /*define the markers: Human, computer*/
hm=aChar(hm,'human'); cm=aChar(cm,'computer') /*process/define markers for players. */
parse upper value hm cm with uh uc /*use uppercase values is markers: X x*/
N = abs(N) /*if N < 0. then computer goes first. */
NN = N*N /*calculate the square of N. */
middle = NN % 2 + N % 2 /* " " middle " the grid. */
if N<2 then do; say oops 'tictactoe grid is too small: ' N; exit 13; end
pad=left('', sw % NN) /*display padding: 6x6 in 80 columns.*/
if hm=='' then hm= "X"; /*define the marker for a human. */
if cm=='' then cm= "O" /* " " " " the computer. */
hm= aChar(hm, 'human') /*determine if the marker is legitimate*/
cm= aChar(cm, 'computer') /* " " " " " " */
parse upper value hm cm with uh uc /*use uppercase values is markers: X x*/
if uh==uc then cm=word('O X', 1 + (uh=="O") ) /*The human wants Hal's marker? Swap. */
if oN<0 then call Hmove middle /*Hal moves first? Then choose middling*/
else call showGrid /*showGrid also checks for wins & draws*/
do forever /*'til the cows come home (or QUIT). */
call CBLF /*process carbon-based lifeform's move.*/
call Hal /*determine Hal's (the computer) move.*/
end /*forever*/ /*showGrid subroutine does wins & draws*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
ab: parse arg bx; if bx\==' ' then return bx /*test if the marker isn't a blank.*/
say oops 'character code for' whoseX "marker can't be a blank."
exit /*stick a fork in it, we're all done. */
if oN<0 then call Hmove middle /*Hal moves first? Then choose middling*/
else call showGrid /*showGrid also checks for wins & draws*/
/*tic─tac─toe game───►*/ do forever /*'til the cows come home (or QUIT). */
/*tic─tac─toe game───►*/ call CBLF /*process carbon─based lifeform's move.*/
/*tic─tac─toe game───►*/ call Hal /*determine Hal's (the computer) move.*/
/*tic─tac─toe game───►*/ end /*forever*/ /*showGrid subroutine does wins & draws*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
aChar: parse arg x,whoseX; L=length(x) /*process markers.*/
if L==1 then return ab(x) /*1 char, as is. */
if L==2 & datatype(x,'X') then return ab(x2c(x)) /*2 chars, hex. */
if L==3 & datatype(x,'W') then return ab(d2c(x)) /*3 chars, decimal*/
say oops 'illegal character or character code for' whoseX "marker: " x
exit /*stick a fork in it, we're all done. */
if L==1 then return testB( x ) /*1 char, as is. */
if L==2 & datatype(x, 'X') then return testB( x2c(x) ) /*2 chars, hex. */
if L==3 & datatype(x, 'W') & , /*3 chars, decimal*/
x>=0 & x<256 then return testB( d2c(x) ) /*···and in range.*/
say oops 'illegal character or character code for' whoseX "marker: " x
exit 13 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
CBLF : prompt='Please enter a' cell@ "to place your next marker ["hm'] (or Quit):'
do forever; say $ prompt; parse pull x 1 ux 1 ox; upper ux
if datatype(ox,'W') then ox=ox/1 /*maybe normalize cell number: +0007. */
select
when abbrev('QUIT',ux,1) then call tell 'quitting.'
when x='' then iterate /*Nada? Try again.*/
when words(x)\==1 then say oops "too many" cell# 'specified:' x
when \datatype(x,'N') then say oops cell@ "isn't numeric: " x
when \datatype(x,'W') then say oops cell@ "isn't an integer: " x
when x=0 then say oops cell@ "can't be zero: " x
when x<0 then say oops cell@ "can't be negative: " x
when x>NN then say oops cell@ "can't exceed " NN
when @.ox\=='' then say oops cell@ "is already occupied: " x
otherwise leave /*forever*/
CBLF: prompt='Please enter a cell number to place your next marker ['hm"] (or Quit):"
do forever; say $ prompt
parse pull x 1 ux 1 ox; upper ux /*get versions of answer; uppercase ux*/
if datatype(ox, 'W') then ox=ox / 1 /*normalize cell number: +0007 ───► 7 */
/*(division by unity normalizes a num.)*/
select /*perform some validations of X (cell#)*/
when abbrev('QUIT',ux,1) then call tell 'quitting.'
when x='' then iterate /*Nada? Try again.*/
when words(x)\==1 then say oops "too many" cell# 'specified:' x
when \datatype(x, 'N') then say oops "cell number isn't numeric: " x
when \datatype(x, 'W') then say oops "cell number isn't an integer: " x
when x=0 then say oops "cell number can't be zero: " x
when x<0 then say oops "cell number can't be negative: " x
when x>NN then say oops "cell number can't exceed " NN
when @.ox\=='' then say oops "cell number is already occupied: " x
otherwise leave /*forever*/
end /*select*/
end /*forever*/
/* [↓] OX is a normalized version of X*/
@.ox=hm /*place a marker for the human (CLBF). */
call showGrid /*and display the tic─tac─toe grid. */
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
Hal: select /*Hal tries various moves. */
when win(cm,N-1) then call Hmove , ec /*is this the winning move?*/
when win(hm,N-1) then call Hmove , ec /* " " a blocking " */
when @.middle=='' then call Hmove middle /*pick the center move. */
when @.N.N=='' then call Hmove , N N /*bottom right corner move.*/
when @.N.1=='' then call Hmove , N 1 /* " left " " */
when @.1.N=='' then call Hmove , 1 N /* top right " " */
when @.1.1=='' then call Hmove , 1 1 /* " left " " */
otherwise call Hmove , ac /*pick a blank cell " */
when win(cm, N-1) then call Hmove , ec /*is this the winning move?*/
when win(hm, N-1) then call Hmove , ec /* " " a blocking " */
when @.middle== '' then call Hmove middle /*pick the center cell. */
when @.N.N == '' then call Hmove , N N /*bottom right corner cell.*/
when @.N.1 == '' then call Hmove , N 1 /* " left " " */
when @.1.N == '' then call Hmove , 1 N /* top right " " */
when @.1.1 == '' then call Hmove , 1 1 /* " left " " */
otherwise call Hmove , ac /*pick a blank cell in grid*/
end /*select*/
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
Hmove: parse arg Hplace,dr dc; if Hplace=='' then Hplace = (dr-1)*N + dc
Hmove: parse arg Hplace,dr dc; if Hplace=='' then Hplace = (dr - 1)*N + dc
@.Hplace=cm /*place computer's marker. */
say; say $ 'computer places a marker ['cm"] at" cell@ ' ' Hplace
say; say $ 'computer places a marker ['cm"] at cell number " Hplace
call showGrid
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
showGrid: _=0; open=0; cW=5; cH=3 /*cell width, cell height.*/
do r=1 for N; do c=1 for N; _=_+1; @.r.c=@._; open=open|@._==''; end
end /*r*/
showGrid: _=0; cW=5; cH=3; open=0 /*cell width, cell height.*/
do r=1 for N /*construct array of cells.*/
do c=1 for N; _=_ + 1; @.r.c=@._; open=open | @._==''
end /*c*/
end /*r*/ /* [↑] OPEN≡a cell is open*/
say /* [↑] create grid coörds.*/
z=0; do j=1 for N /* [↓] show grids&markers.*/
do t=1 for cH; _=; __= /*MK is a marker in a cell.*/
do k=1 for N; if t==2 then z=z+1; mk=; c#=
if t==2 then do; mk=@.z; c#=z; end /*c# is cell number*/
_= _||jam||center(mk,cW); __= __ || jam || center(c#, cW)
do k=1 for N; if t==2 then z=z + 1; mk=; c#=
if t==2 then do; mk=@.z; c#=z /*c# is cell number*/
end
_= _ || jam || center(mk, cW)
__= __ || jam || center(c#, cW)
end /*k*/
say pad substr(_,2) pad translate(substr(__,2), sing,dbl)
end /*t*/
if j==N then leave; _=
do b=1 for N; _=_ || junc || copies(bar, cW); end /*b*/
say pad substr(_,2) pad translate(substr(_,2), sing, dbl)
say pad substr(_, 2) pad translate( substr(__, 2), single, dbl)
end /*t*/ /* [↑] show a line*/
if j==N then leave
_=
do b=1 for N; _=_ || junc || copies(bar, cW)
end /*b*/ /* [↑] a grid part*/
say pad substr(_, 2) pad translate( substr(_, 2), single, dbl)
end /*j*/
say
if win(hm) then call tell 'You ('hm") won!"
if win(hm) then call tell 'You ('hm") won"copies('!',random(1, 5) )
if win(cm) then call tell 'The computer ('cm") won."
if \open then call tell 'This tictactoe game is a draw.'
if \open then call tell 'This tictactoe game is a draw (a cat scratch).'
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
tell: do 4; say; end; say center(' 'arg(1)" ", sw, ''); do 5; say; end; exit
tell: do 4; say; end; say center(' 'arg(1)" ", sw, ''); do 5; say; end; exit
/*──────────────────────────────────────────────────────────────────────────────────────*/
win: parse arg wm,w; if w=='' then w=N /*see if there are W of markers*/
ac=; do r=1 for N; _=0; ec= /*see if any rows are a winner*/
do c=1 for N; _=_+ (@.r.c==wm); if @.r.c=='' then ec=r c; end
if ec\=='' then ac=ec; if _==N | (_>=w & ec\=='') then return 1
end /*r*/ /*w=N-1? Checking for near win*/
do c=1 for N; _=0; ec= /*see if any cols are a winner*/
do r=1 for N; _=_+ (@.r.c==wm); if @.r.c=='' then ec=r c; end
if ec\=='' then ac=ec; if _==N | (_>=w & ec\=='') then return 1
end /*r*/ /*EC is a R,C version of cell #*/
_=0; ec= /*A winning descending diag. ? */
do d=1 for N; _=_+ (@.d.d==wm); if @.d.d=='' then ec=d d; end
if _==N | (_>=w & ec\=='') then return 1
_=0; ec=; r=0 /*A winning ascending diagonal?*/
do c=N for N by -1; r=r+1; _=_+ (@.r.c==wm); if @.r.c=='' then ec=r c
end /*r*/
if _==N | (_>=w & ec\=='') then return 1
return 0
testB: parse arg bx; if bx\==' ' then return bx /*test if the marker isn't a blank.*/
say oops 'character code for' whoseX "marker can't be a blank."
exit 13 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
win: parse arg wm,w; if w=='' then w=N /* [↓] see if there is a win. */
ac= /* [↓] EC ≡ means Empty Cell. */
do r=1 for N; _=0; ec= /*see if any rows are a winner*/
do c=1 for N; _=_ + (@.r.c==wm) /*count the # of markers in col*/
if @.r.c=='' then ec=r c /*Cell empty? Then remember it*/
end /*c*/ /* [↓] AX≡means avaiable cell.*/
if ec\=='' then ac=ec /*Found an empty? Then use it.*/
if _==N | (_>=w & ec\=='') then return 1=1 /*a winner has been determined.*/
end /*r*/ /*w=N-1? Checking for near win*/
do c=1 for N; _=0; ec= /*see if any cols are a winner*/
do r=1 for N; _=_ + (@.r.c==wm) /*count the # of markers in row*/
if @.r.c=='' then ec=r c /*Cell empty? Then remember it*/
end /*r*/
if ec\=='' then ac=ec /*Found an empty? Then remember*/
if _==N | (_>=w & ec\=='') then return 1=1 /*a winner has been determined.*/
end /*c*/
_=0
ec= /*EC≡location of an empty cell.*/
do d=1 for N; _=_ + (@.d.d==wm) /*A winning descending diag. ? */
if @.d.d=='' then ec=d d /*Empty cell? Then note cell #*/
end /*d*/
if _==N | (_>=w & ec\=='') then return 1=1 /*a winner has been determined.*/
_=0; r=1
do c=N for N by -1; _=_ + (@.r.c==wm) /*A winning ascending diagonal?*/
if @.r.c=='' then ec=r c /*Empty cell? Then note cell #*/
r=r + 1 /*bump the counter for the rows*/
end /*c*/
if _==N | (_>=w & ec\=='') then return 1=1 /*a winner has been determined.*/
return 0 /*no winner " " " */

View file

@ -39,7 +39,7 @@ class Board(aBoard : List[Char] = BaseBoard) {
}
object TicTacToe extends Application {
object TicTacToe extends App {
def play(board : Board, turn : Char) {

View file

@ -0,0 +1,126 @@
Option Explicit
Private Lines(1 To 3, 1 To 3) As String
Private Nb As Byte, player As Byte
Private GameWin As Boolean, GameOver As Boolean
Sub Main_TicTacToe()
Dim p As String
InitLines
printLines Nb
Do
p = WhoPlay
Debug.Print p & " play"
If p = "Human" Then
Call HumanPlay
GameWin = IsWinner("X")
Else
Call ComputerPlay
GameWin = IsWinner("O")
End If
If Not GameWin Then GameOver = IsEnd
Loop Until GameWin Or GameOver
If Not GameOver Then
Debug.Print p & " Win !"
Else
Debug.Print "Game Over!"
End If
End Sub
Sub InitLines(Optional S As String)
Dim i As Byte, j As Byte
Nb = 0: player = 0
For i = LBound(Lines, 1) To UBound(Lines, 1)
For j = LBound(Lines, 2) To UBound(Lines, 2)
Lines(i, j) = "#"
Next j
Next i
End Sub
Sub printLines(Nb As Byte)
Dim i As Byte, j As Byte, strT As String
Debug.Print "Loop " & Nb
For i = LBound(Lines, 1) To UBound(Lines, 1)
For j = LBound(Lines, 2) To UBound(Lines, 2)
strT = strT & Lines(i, j)
Next j
Debug.Print strT
strT = vbNullString
Next i
End Sub
Function WhoPlay(Optional S As String) As String
If player = 0 Then
player = 1
WhoPlay = "Human"
Else
player = 0
WhoPlay = "Computer"
End If
End Function
Sub HumanPlay(Optional S As String)
Dim L As Byte, C As Byte, GoodPlay As Boolean
Do
L = Application.InputBox("Choose the row", "Numeric only", Type:=1)
If L > 0 And L < 4 Then
C = Application.InputBox("Choose the column", "Numeric only", Type:=1)
If C > 0 And C < 4 Then
If Lines(L, C) = "#" And Not Lines(L, C) = "X" And Not Lines(L, C) = "O" Then
Lines(L, C) = "X"
Nb = Nb + 1
printLines Nb
GoodPlay = True
End If
End If
End If
Loop Until GoodPlay
End Sub
Sub ComputerPlay(Optional S As String)
Dim L As Byte, C As Byte, GoodPlay As Boolean
Randomize Timer
Do
L = Int((Rnd * 3) + 1)
C = Int((Rnd * 3) + 1)
If Lines(L, C) = "#" And Not Lines(L, C) = "X" And Not Lines(L, C) = "O" Then
Lines(L, C) = "O"
Nb = Nb + 1
printLines Nb
GoodPlay = True
End If
Loop Until GoodPlay
End Sub
Function IsWinner(S As String) As Boolean
Dim i As Byte, j As Byte, Ch As String, strTL As String, strTC As String
Ch = String(UBound(Lines, 1), S)
'check lines & columns
For i = LBound(Lines, 1) To UBound(Lines, 1)
For j = LBound(Lines, 2) To UBound(Lines, 2)
strTL = strTL & Lines(i, j)
strTC = strTC & Lines(j, i)
Next j
If strTL = Ch Or strTC = Ch Then IsWinner = True: Exit For
strTL = vbNullString: strTC = vbNullString
Next i
'check diagonales
strTL = Lines(1, 1) & Lines(2, 2) & Lines(3, 3)
strTC = Lines(1, 3) & Lines(2, 2) & Lines(3, 1)
If strTL = Ch Or strTC = Ch Then IsWinner = True
End Function
Function IsEnd() As Boolean
Dim i As Byte, j As Byte
For i = LBound(Lines, 1) To UBound(Lines, 1)
For j = LBound(Lines, 2) To UBound(Lines, 2)
If Lines(i, j) = "#" Then Exit Function
Next j
Next i
IsEnd = True
End Function