September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

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

View file

@ -1,2 +1,4 @@
---
category:
- Games
note: Games

View file

@ -0,0 +1,31 @@
alias ttt {
if ($2 isin %ttt) || (!%ttt) {
var %ttt~ = $remove($iif(%ttt,%ttt,1 2 3 4 5 6 7 8 9),$2,X,O)
var %ttt~~ = $replace($iif(%ttt,%ttt,1 2 3 4 5 6 7 8 9),$2,X)
set %ttt $replace(%ttt~~,$iif(($regex(%ttt~~,/(?:O . . (?:(?:. O .|O) . . (\d)|(?:. (\d) .|(\d)) . . O)|(\d) . . (?:. O .|O) . . O|. . (?:O . (?:O . (\d)|(\d) . O)|(\d) . O . O) . .)/)) || ($regex(%ttt~~,/^(?:. . . )*(?:O (?:O (\d)|(\d) O)|(\d) O O)(?: . . .)*$/)),$regml(1),$iif(($regex(%ttt~~,/(?:X . . (?:(?:. X .|X) . . (\d)|(?:. (\d) .|(\d)) . . X)|(\d) . . (?:. X .|X) . . X|. . (?:X . (?:X . (\d)|(\d) . X)|(\d) . X . X) . .)/)) || ($regex(%ttt~~,/^(?:. . . )*(?:X (?:X (\d)|(\d) X)|(\d) X X)(?: . . .)*$/)),$regml(1),$iif($remove(%ttt~,2,4,6,8,$chr(32)),$iif((5 isin $remove(%ttt~,2,4,6,8)) && ($rand(0,$numtok($v2,32)) == 0),5,$gettok($remove(%ttt~,2,4,6,8),$rand(1,$numtok($remove(%ttt~,2,4,6,8),32)),32)),$gettok(%ttt~,$rand(1,$numtok(%ttt~,32)),32)))),O)
tokenize 32 %ttt
if ($regex(%ttt,/(?:X . . (?:X|. X .) . . X|. . X . X . X . .)/)) || ($regex(%ttt,/^(?:. . . )*X X X(?: . . .)*$/)) {
echo -ag $me Wins
tokenize 32 %ttt~~
unset %ttt
}
elseif ($regex(%ttt,/(?:O . . (?:O|. O .) . . O|. . O . O . O . .)/)) || ($regex(%ttt,/^(?:. . . )*O O O(?: . . .)*$/)) {
echo -ag $me Loses
unset %ttt
}
elseif (!$regex(%ttt,/\d/)) {
echo -ag Draw
unset %ttt
}
echo -ag <20> $+ $iif($1 isnum,$chr(32),$1) $+ $chr(124) $+ $iif($2 isnum,$chr(32),$2) $+ $chr(124) $+ $iif($3 isnum, ,$3)
echo -ag <20> $+ $iif($4 isnum,$chr(32),$4) $+ $chr(124) $+ $iif($5 isnum,$chr(32),$5) $+ $chr(124) $+ $iif($6 isnum, ,$6)
echo -ag <20> $+ $iif($7 isnum,$chr(32),$7) $+ $chr(124) $+ $iif($8 isnum,$chr(32),$8) $+ $chr(124) $+ $iif($9 isnum, ,$9)
}
else {
echo -ag Place Taken
tokenize 32 %ttt
echo -ag <20> $+ $iif($1 isnum,$chr(32),$1) $+ $chr(124) $+ $iif($2 isnum,$chr(32),$2) $+ $chr(124) $+ $iif($3 isnum, ,$3)
echo -ag <20> $+ $iif($4 isnum,$chr(32),$4) $+ $chr(124) $+ $iif($5 isnum,$chr(32),$5) $+ $chr(124) $+ $iif($6 isnum, ,$6)
echo -ag <20> $+ $iif($7 isnum,$chr(32),$7) $+ $chr(124) $+ $iif($8 isnum,$chr(32),$8) $+ $chr(124) $+ $iif($9 isnum, ,$9)
}
}

View file

@ -0,0 +1,379 @@
function [] = startGame()
//Board size and marks
N = 3;
marks = ["X" "O"];
//Creating empty board
board = string(zeros(N,N));
for i = 1:(N*N)
board(i) = "";
end
//Initialising players
clc();
players= [%F %F];
players = playerSetup(marks);
//Console header
header = [strsplit(marks(1)+" is ----")';...
strsplit(marks(2)+" is ----")'];
for i = 1:2
if players(i) then
header(i,6:10) = strsplit("P"+string(i)+". ");
else
header(i,6:10) = strsplit("COMP.");
end
end
//Game loop
sleep(1000);
win_flag = %F;
count = 0;
while count<N*N
//Clear console, and print header and board
clc();
printf("%s\n %s\n",strcat(header(1,:)),strcat(header(2,:)));
dispBoard(board);
//Find which player should move
player_n = modulo(count,2) + 1;
if players(player_n) == %T then
//Human plays
pos = [];
valid_move = %F;
disp(marks(player_n)+"''s turn.");
while valid_move ~= %T
[pos,valid_move] = readHumanMove(board);
if ~valid_move then
disp("You should input a valid cell number.");
end
end
if valid_move then
board = updateBoard(board,pos,marks(player_n));
else
error("Invalid move.");
end
else
//Computer plays
disp("Computer is playing.");
board = ComputerMove(board,marks(player_n),marks);
sleep(800);
end
//Count number of movements
count = count + 1;
//Check if the game has finished
[win_flag,winning_mark] = detectWin(board)
if win_flag then
break
end
end
//Clear screen at the end of game
clc();
disp("Game finished:");
dispBoard(board);
//Print results
if win_flag then
disp(winning_mark+" won!");
else
disp("It''s a tie.");
end
//Play again?
play_again = "";
while play_again ~= "Y" & play_again ~= "N"
play_again = input("Would you like to play again? (Y/N)","s");
play_again = strsplit(play_again);
play_again = convstr(play_again(1),"u");
if play_again ~= "Y" & play_again ~= "N" then
disp("Invalid answer.");
end
end
if play_again == "Y" then
startGame();
else
disp("Quit game.");
end
endfunction
function players = playerSetup(marks)
//Determines who plays which mark
players = [%F %F]; //True for human, Flase for computer
printf("\n%s always starts.\n",marks(1));
for i = 1:2
user_input = "";
while user_input ~= "Y" & user_input ~= "N"
user_input = input("Would you like to play as "+marks(i)+"? (Y/N)","s");
user_input = strsplit(user_input);
user_input = convstr(user_input(1),"u");
if user_input ~= "Y" & user_input ~= "N" then
disp("Invalid answer.");
end
end
//Print choice
if user_input == "Y" then
players(i) = %T;
printf("%s shall be player %d (P%d).\n\n",marks(i),i,i);
else
printf("%s shall be the computer (COMP).\n\n",marks(i));
end
end
endfunction
function [] = dispBoard(board)
//Print ASCII board on console
//Get board marks
marks = [" " " "];
mark_inds = find(board ~= "");
if mark_inds ~= [] then
marks(1) = board(mark_inds(1));
mark_inds = find( (board ~= "") & (board ~= marks(1)) );
if mark_inds ~= [] then
marks(2) = board(mark_inds(1));
end
end
//Transpose to display for humans
//[compatibility with readHumanMove()]
disp_board = board';
rows = 3*size(board,'r');
cols = 4*size(board,'c');
ascii_board = string(zeros(rows, cols));
mark_1=[...
strsplit(" |")';...
strsplit(" "+marks(1)+" |")';...
strsplit("___|")'];
mark_2=[...
strsplit(" |")';...
strsplit(" "+marks(2)+" |")';...
strsplit("___|")'];
Blank_mark=[...
strsplit(" |")';...
strsplit(" |")';...
strsplit("___|")'];
for r = ([1:size(board,'r')] - 1 )
for c = ([1:size(board,'c')] - 1)
if disp_board(r+1,c+1) == marks(1) then
ascii_board((r*3 + 1):((r+1)*3),...
(c*4 + 1):((c+1)*4)) = mark_1;
elseif disp_board(r+1,c+1) == marks(2) then
ascii_board((r*3 + 1):((r+1)*3),...
(c*4 + 1):((c+1)*4)) = mark_2;
else
ascii_board((r*3 + 1):((r+1)*3),...
(c*4 + 1):((c+1)*4)) = Blank_mark;
end
end
end
for i = 1:cols
if modulo(i,4)>0 then
ascii_board(rows,i) = " ";
end
end
for i = 1:rows
ascii_board(i,cols) = " ";
end
printf("\n");
for i = 1:size(ascii_board,'r')
printf("%s\n",strcat(ascii_board(i,:)))
end
endfunction
function moves_board = availableMoves(board)
//Find empty cells on the board
moves_board = board;
for i = 1:(size(board,'r')*size(board,'c'))
if board(i) == "" then
moves_board(i) = string(i);
else
moves_board(i) = "_";
end
end
endfunction
function varargout = readHumanMove(board)
//Read human input
printf("\nAvailable cells:");
moves_board = availableMoves(board);
disp(moves_board');
x = input("\nEnter a move (0 to quit game): ");
valid = %F;
pos = 0;
total = size(moves_board,'r') * size(moves_board,'c');
//Check if it is a valid move
if x == 0 then
disp("Quit game.")
abort
elseif (x>=1 & x<=total) then
if (moves_board(x) == string(x)) then
valid = %T;
pos = x;
end
end
varargout = list(pos,valid);
endfunction
function varargout = updateBoard(board,pos,player)
//Add move to the board
if board(pos) ~= "" then
error('Error: Invalid move.');
end
board(pos) = player
varargout = list(board);
endfunction
function varargout = detectWin(board)
//Detect if there is a winner or not
win_flag = %F;
winner = "";
//Get board marks
marks = ["" ""];
mark_inds = find(board ~= "");
marks(1) = board(mark_inds(1))
mark_inds = find( (board ~= "") & (board ~= marks(1)) );
marks(2) = board(mark_inds(1));
//If there is a minimum number of moves, check if there is a winner
n_moves = find(~(board == ""));
n_moves = length(n_moves)
if n_moves >= size(board,'r') then
board_X = (board == marks(1));
board_O = (board == marks(2));
for i = 1:size(board,'r')
//Check rows
if find(~board_X(i,:)) == [] then
win_flag = %T;
winner = marks(1);
break
end
if find(~board_O(i,:)) == [] then
win_flag = %T;
winner = marks(2);
break
end
//Check columns
if find(~board_X(:,i)) == [] then
win_flag = %T;
winner = marks(1);
break
end
if find(~board_O(:,i)) == [] then
win_flag = %T;
winner = marks(2);
break
end
end
//Check diagonal
if ~win_flag then
if find(~diag(board_X)) == [] then
win_flag = %T;
winner = marks(1);
elseif find(~diag(board_O)) == [] then
win_flag = %T;
winner = marks(2);
end
end
//Check anti-diagonal
if ~win_flag then
board_X = board_X(:,$:-1:1);
board_O = board_O(:,$:-1:1);
if find(~diag(board_X)) == [] then
win_flag = %T;
winner = marks(1);
elseif find(~diag(board_O)) == [] then
win_flag = %T;
winner = marks(2);
end
end
end
varargout = list(win_flag,winner)
endfunction
function threat_pos = findThreat(board,player)
//Returns a list of moves that can finish the game
//Available moves
move_inds = find(~( availableMoves(board) == "_" ));
//If there is a minimum number of moves, check if there is a threat
threat_pos = [];
if (size(board,'r')*size(board,'c')) - length(move_inds) >...
(size(board,'r') - 1) then
for i = 1:length(move_inds)
temp_board = updateBoard(board,move_inds(i),player);
[win_flag,winner] = detectWin(temp_board);
if win_flag & winner == player then
threat_pos = [threat_pos move_inds(i)];
end
end
end
endfunction
function varargout = ComputerMove(board,mark,all_marks)
//Atomatically add a move to the board with no human input
//Find winning moves moves
move_inds = findThreat(board,mark);
//If there are no winning moves, find opponent's winning moves
//to block opponent's victory
if move_inds == [] then
if mark == all_marks(1) then
opponent = all_marks(2);
elseif mark == all_marks(2) then
opponent = all_marks(1);
end
move_inds = findThreat(board,opponent);
end
//If there are no winning moves or threats, find all possible moves
if move_inds == [] then
move_inds = find(~( availableMoves(board) == "_" ));
end
//Choose a random move among the selected possible moves
pos = grand(1,"prm",move_inds);
pos = pos(1);
//Update board by adding a new mark
board(pos) = mark;
varargout = list(board);
endfunction
startGame()

View file

@ -0,0 +1,206 @@
import Darwin
enum Token : CustomStringConvertible {
case cross, circle
func matches(tokens: [Token?]) -> Bool {
for token in tokens {
guard let t = token, t == self else {
return false
}
}
return true
}
func emptyCell(in tokens: [Token?]) -> Int? {
if tokens[0] == nil
&& tokens[1] == self
&& tokens[2] == self {
return 0
} else
if tokens[0] == self
&& tokens[1] == nil
&& tokens[2] == self {
return 1
} else
if tokens[0] == self
&& tokens[1] == self
&& tokens[2] == nil {
return 2
}
return nil
}
var description: String {
switch self {
case .cross: return "x"
case .circle: return "o"
}
}
}
struct Board {
var cells: [Token?] = [nil, nil, nil, nil, nil, nil, nil, nil, nil]
func cells(atCol col: Int) -> [Token?] {
return [cells[col], cells[col + 3], cells[col + 6]]
}
func cells(atRow row: Int) -> [Token?] {
return [cells[row * 3], cells[row * 3 + 1], cells[row * 3 + 2]]
}
func cellsTopLeft() -> [Token?] {
return [cells[0], cells[4], cells[8]]
}
func cellsBottomLeft() -> [Token?] {
return [cells[6], cells[4], cells[2]]
}
func winner() -> Token? {
let r0 = cells(atRow: 0)
let r1 = cells(atRow: 1)
let r2 = cells(atRow: 2)
let c0 = cells(atCol: 0)
let c1 = cells(atCol: 1)
let c2 = cells(atCol: 2)
let tl = cellsTopLeft()
let bl = cellsBottomLeft()
if Token.cross.matches(tokens: r0)
|| Token.cross.matches(tokens: r1)
|| Token.cross.matches(tokens: r2)
|| Token.cross.matches(tokens: c0)
|| Token.cross.matches(tokens: c1)
|| Token.cross.matches(tokens: c2)
|| Token.cross.matches(tokens: tl)
|| Token.cross.matches(tokens: bl) {
return .cross
} else
if Token.circle.matches(tokens: r0)
|| Token.circle.matches(tokens: r1)
|| Token.circle.matches(tokens: r2)
|| Token.circle.matches(tokens: c0)
|| Token.circle.matches(tokens: c1)
|| Token.circle.matches(tokens: c2)
|| Token.circle.matches(tokens: tl)
|| Token.circle.matches(tokens: bl) {
return .circle
}
return nil
}
func atCapacity() -> Bool {
return cells.filter { $0 == nil }.count == 0
}
mutating func play(token: Token, at location: Int) {
cells[location] = token
}
func findBestLocation(for player: Token) -> Int? {
let r0 = cells(atRow: 0)
let r1 = cells(atRow: 1)
let r2 = cells(atRow: 2)
let c0 = cells(atCol: 0)
let c1 = cells(atCol: 1)
let c2 = cells(atCol: 2)
let tl = cellsTopLeft()
let bl = cellsBottomLeft()
if let cell = player.emptyCell(in: r0) {
return cell
} else if let cell = player.emptyCell(in: r1) {
return cell + 3
} else if let cell = player.emptyCell(in: r2) {
return cell + 6
} else if let cell = player.emptyCell(in: c0) {
return cell * 3
} else if let cell = player.emptyCell(in: c1) {
return cell * 3 + 1
} else if let cell = player.emptyCell(in: c2) {
return cell * 3 + 2
} else if let cell = player.emptyCell(in: tl) {
return cell == 0 ? 0 : (cell == 1 ? 4 : 8)
} else if let cell = player.emptyCell(in: bl) {
return cell == 0 ? 6 : (cell == 1 ? 4 : 2)
}
return nil
}
func findMove() -> Int {
let empties = cells.enumerated().filter { $0.1 == nil }
let r = Int(arc4random()) % empties.count
return empties[r].0
}
}
extension Board : CustomStringConvertible {
var description: String {
var result = "\n---------------\n"
for (idx, cell) in cells.enumerated() {
if let cell = cell {
result += "| \(cell) |"
} else {
result += "| \(idx) |"
}
if (idx + 1) % 3 == 0 {
result += "\n---------------\n"
}
}
return result
}
}
while true {
var board = Board()
print("Who do you want to play as ('o' or 'x'): ", separator: "", terminator: "")
let answer = readLine()?.characters.first ?? "x"
var player: Token = answer == "x" ? .cross : .circle
var pc: Token = player == .cross ? .circle : .cross
print(board)
while true {
print("Choose cell to play on: ", separator: "", terminator: "")
var pos = Int(readLine() ?? "0") ?? 0
while !board.atCapacity() && board.cells[pos] != nil {
print("Invalid move. Choose cell to play on: ", separator: "", terminator: "")
pos = Int(readLine() ?? "0") ?? 0
}
if board.atCapacity() {
print("Draw")
break
}
board.play(token: player, at: pos)
print(board)
if let winner = board.winner() {
print("winner is \(winner)")
break
} else if board.atCapacity() {
print("Draw")
break
}
if let win = board.findBestLocation(for: pc) {
board.play(token: pc, at: win)
} else if let def = board.findBestLocation(for: player) {
board.play(token: pc, at: def)
} else {
board.play(token: pc, at: board.findMove())
}
print(board)
if let winner = board.winner() {
print("winner is \(winner)")
break
}
}
}