Darren Tsai
National Taipei University
rm(list=ls())
library(RColorBrewer)
########################
# tic.tac.toe function #
########################
tic.tac.toe <- function(name="Name", mode=0, type=0){
place.na <<- matrix(1:9, 3, 3)
value <<- matrix(-3, 3, 3)
k <<- 1 ; r <<- 0
#########################
# Plot Tic-Tac-Toe form #
#########################
image(1:3, 1:3, matrix(sample(9), 3, 3), asp=c(1, 1),
xaxt="n", yaxt="n", xlab="", ylab="", frame=F, col=brewer.pal(9, "Set3"))
segments(c(0.5,0.5,1.5,2.5), c(2.5,1.5,0.5,0.5),
c(3.5,3.5,1.5,2.5), c(2.5,1.5,3.5,3.5), lwd=8, col=gray(0.3))
segments(c(0.5,0.5,0.5,3.5), c(0.52,3.47,0.5,0.5),
c(3.5,3.5,0.5,3.5), c(0.52,3.47,3.5,3.5), lwd=8, col=gray(0.3))
###########
# 1P & 2P #
###########
if(mode==0) title(list(paste(name, "'s Tic-Tac-Toe !"), cex=2),
"2P : Human v.s. Human", font.sub=2, cex.sub=2)
if(mode==1) title(list(paste(name, "'s Tic-Tac-Toe !"), cex=2),
"1P : Human v.s. AI (Easy)", font.sub=2, cex.sub=2)
if(mode==2) title(list(paste(name, "'s Tic-Tac-Toe !"), cex=2),
"1P : Human v.s. AI (Hard)", font.sub=2, cex.sub=2)
#########
# O & X #
#########
if(type==0){symbol <- "O" ; symbol.op <- "X"}
if(type==1){symbol <- "X" ; symbol.op <- "O"}
out <- list(name=name, mode=mode, type=type, symbol=symbol, symbol.op=symbol.op)
}
##########################
# identification of line #
##########################
line <- function(){
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==0 | total.2==0 | total.1==3 | total.2==3){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==0 | total.2==0 | total.3==0 | total.4==0 | total.1==3 | total.2==3 | total.3==3 | total.4==3){
place.na[!is.na(place.na)] <<- NA
if(total.1==0 | total.2==0 | total.3==0 | total.4==0){
title(sub=list("You Win ! Game Over !", col="red", font=2, cex=2.5), line=2)
}else{
title(sub=list("You Are a Loser !", col="darkblue", font=2, cex=2.5), line=2)
}
}
if(all(is.na(place.na))){
if(total.1==0 | total.2==0 | total.3==0 | total.4==0 | total.1==3 | total.2==3 | total.3==3 | total.4==3){
if(total.1==0 | total.2==0 | total.3==0 | total.4==0){
title(sub=list("You Win ! Game Over !", col="orange", font=2, cex=2.5), line=2)
}else{
title(sub=list("You Are a Loser !", col="darkblue", font=2, cex=2.5), line=2)
}
}else{
title(sub=list("Draw ! Please try again !", col="blue", font=2, cex=2.5), line=2)
}
}
}
#############
# AI attack #
#############
attack <- function(){
### Identify rows and columns
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-1 | total.2==-1){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==-1){
text(i, which(value[i,]!=1), symbol.op, cex=6, font=2)
place.na[i, which(value[i,]!=1)] <<- NA
value[i, which(value[i,]!=1)] <<- 1
}else if(total.2==-1){
text(which(value[,i]!=1), i, symbol.op, cex=6, font=2)
place.na[which(value[,i]!=1), i] <<- NA
value[which(value[,i]!=1), i] <<- 1
}else if(total.3==-1){
r.1 <- which(c(value[1, 1], value[2, 2], value[3, 3])!=1)
text(r.1, r.1, symbol.op, cex=6, font=2)
place.na[r.1, r.1] <<- NA
value[r.1, r.1] <<- 1
}else if(total.4==-1){
r.2 <- which(c(value[1, 3], value[2, 2], value[3, 1])!=1)
text(r.2, -r.2+4, symbol.op, cex=6, font=2)
place.na[r.2, -r.2+4] <<- NA
value[r.2, -r.2+4] <<- 1
}
}
#############
# AI defend #
#############
defend <- function(){
### Identify rows and columns
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-3 | total.2==-3){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==-3){
text(i, which(value[i,]!=0), symbol.op, cex=6, font=2)
place.na[i, which(value[i,]!=0)] <<- NA
value[i, which(value[i,]!=0)] <<- 1
}else if(total.2==-3){
text(which(value[,i]!=0), i, symbol.op, cex=6, font=2)
place.na[which(value[,i]!=0), i] <<- NA
value[which(value[,i]!=0), i] <<- 1
}else if(total.3==-3){
r.1 <- which(c(value[1, 1], value[2, 2], value[3, 3])!=0)
text(r.1, r.1, symbol.op, cex=6, font=2)
place.na[r.1, r.1] <<- NA
value[r.1, r.1] <<- 1
}else if(total.4==-3){
r.2 <- which(c(value[1, 3], value[2, 2], value[3, 1])!=0)
text(r.2, -r.2+4, symbol.op, cex=6, font=2)
place.na[r.2, -r.2+4] <<- NA
value[r.2, -r.2+4] <<- 1
}else{
rn <- sample(place.na[!is.na(place.na)], 1)
text(rn-3*rn%/%3.5, rn%/%3.5+1, symbol.op, cex=6, font=2)
place.na[rn-3*rn%/%3.5, rn%/%3.5+1] <<- NA
value[rn-3*rn%/%3.5, rn%/%3.5+1] <<- 1
}
}
################
# aim function #
################
aim <- function(x, y, tic.tac.toe=ttt){
mode <- tic.tac.toe$mode
symbol <<- tic.tac.toe$symbol
symbol.op <<- tic.tac.toe$symbol.op
x <<- x ; y <<- y
################
# mode=0 -> 2P #
################
if(mode==0){
turn <- rep(c(0, 1), length.out=9)
if(is.na(place.na[x, y])){
cat("This square had been chosen !")
}else{
if(turn[k]==0){
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
}
if(turn[k]==1){
text(x, y, symbol.op, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 1
}
k <<- k + 1
}
}
######################
# mode=1 -> AI(easy) #
######################
if(mode==1){
if(is.na(place.na[x, y])){
cat("This square had been chosen !")
}else{
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
line()
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-1 | total.2==-1){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(all(is.na(place.na))){
line()
}else if(total.1==-1 | total.2==-1 | total.3==-1 | total.4==-1){
attack()
}else{
defend()
}
}
}
######################
# mode=2 -> AI(hard) #
######################
if(mode==2){
if(is.na(place.na[x, y])){
cat("This square had been chosen !")
}else{
#################
# AI First turn #
#################
if(sum(is.na(place.na))==0){
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
if(is.na(place.na[2, 2])==F){
text(2, 2, symbol.op, cex=6, font=2)
place.na[2, 2] <<- NA
value[2, 2] <<- 1
}else{
corner.1 <- sample(c(1, 3), 1) ; corner.2 <- sample(c(1, 3), 1)
text(corner.1, corner.2, symbol.op, cex=6, font=2)
place.na[corner.1, corner.2] <<- NA
value[corner.1, corner.2] <<- 1
}
##################
# AI Second turn #
##################
}else if(sum(is.na(place.na))==2){
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-3 | total.2==-3){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==-3 | total.2==-3 | total.3==-3 | total.4==-3){
defend()
}else{
total.1 <- value[2, 1] + value[2, 2] + value[2, 3]
total.2 <- value[1, 2] + value[2, 2] + value[3, 2]
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(total.1==1 | total.2==1 | total.3==1 | total.4==1){
if((value[2, 2]==1 & total.3==1) | (value[2, 2]==1 & total.4==1)){
vector.side <- c(place.na[2, 1], place.na[1, 2], place.na[3, 2], place.na[2, 3])
rn <- sample(vector.side[!is.na(vector.side)], 1)
text(rn-3*rn%/%3.5, rn%/%3.5+1, symbol.op, cex=6, font=2)
place.na[rn-3*rn%/%3.5, rn%/%3.5+1] <<- NA
value[rn-3*rn%/%3.5, rn%/%3.5+1] <<- 1
}else{
matrix.cor <- place.na[c(1, 3), c(1, 3)]
rn <- sample(matrix.cor[!is.na(matrix.cor)], 1)
text(rn-3*rn%/%3.5, rn%/%3.5+1, symbol.op, cex=6, font=2)
place.na[rn-3*rn%/%3.5, rn%/%3.5+1] <<- NA
value[rn-3*rn%/%3.5, rn%/%3.5+1] <<- 1
}
}else{
if((x==1 & y==2) | (x==3 & y==2)){
rn <- sample(c(1, 3), 1)
text(x, rn, symbol.op, cex=6, font=2)
place.na[x, rn] <<- NA
value[x, rn] <<- 1
}else if((x==2 & y==3) | (x==2 & y==1)){
rn <- sample(c(1, 3), 1)
text(rn, y, symbol.op, cex=6, font=2)
place.na[rn, y] <<- NA
value[rn, y] <<- 1
}else if((x==1 & y==1) | (x==1 & y==3) | (x==3 & y==1) | (x==3 & y==3)){
text(-x+4, -y+4, symbol.op, cex=6, font=2)
place.na[-x+4, -y+4] <<- NA
value[-x+4, -y+4] <<- 1
}
}
}
#################
# AI Other turn #
#################
}else{
text(x, y, symbol, cex=6, font=2)
place.na[x, y] <<- NA
value[x, y] <<- 0
line()
for(i in 1:3){
total.1 <- 0 ; total.2 <- 0
for(j in 1:3){
total.1 <- total.1 + value[i, j]
total.2 <- total.2 + value[j, i]
}
if(total.1==-1 | total.2==-1){
break
}
}
total.3 <- value[1, 1] + value[2, 2] + value[3, 3]
total.4 <- value[1, 3] + value[2, 2] + value[3, 1]
if(all(is.na(place.na))){
line()
}else if(total.1==-1 | total.2==-1 | total.3==-1 | total.4==-1){
attack()
}else{
defend()
}
}
}
}
line()
}
##################
# click function #
##################
click <- function(tic.tac.toe=ttt){
name <- tic.tac.toe$name
mode <- tic.tac.toe$mode
type <- tic.tac.toe$type
while(length(place.na)==9){
mouse.at <- locator(n = 1, type = "n")
#cat(mouse.at$x,"\t", mouse.at$y, "\n")
x.at <- round(mouse.at$x)
y.at <- round(mouse.at$y)
#cat(x.at,"\t", y.at, "\n")
if(all(is.na(place.na))){
ttt <<- tic.tac.toe(name, mode, type)
}else if(x.at > 3.5 | x.at < 0.5 | y.at > 3.5 | y.at < 0.5){
r <<- r + 1
title(sub=list("Click outside:Quit / inside:Restart", col="deeppink", font=2, cex=2), line=2)
if(r==2){
dev.off()
break
}
}else{
if(r==1){
ttt <<- tic.tac.toe(name, mode, type)
}else{
aim(x.at, y.at)
}
}
}
}
#################
# Start Game !! #
#################
start <- function(name="Name", mode=0, type=0){
x11()
ttt <<- tic.tac.toe(name, mode, type)
click()
}
# start("Darren", mode=2, type=1)