all tasks
This commit is contained in:
parent
b83f433714
commit
68f8f3e56b
14735 changed files with 178959 additions and 0 deletions
1
Task/Tic-tac-toe/0DESCRIPTION
Normal file
1
Task/Tic-tac-toe/0DESCRIPTION
Normal file
|
|
@ -0,0 +1 @@
|
|||
Play a game of [[wp:Tic-tac-toe|tic-tac-toe]]. Ensure that legal moves are played and that a winning position is notified.
|
||||
2
Task/Tic-tac-toe/1META.yaml
Normal file
2
Task/Tic-tac-toe/1META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
note: Games
|
||||
124
Task/Tic-tac-toe/Ada/tic-tac-toe.ada
Normal file
124
Task/Tic-tac-toe/Ada/tic-tac-toe.ada
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
with Ada.Text_IO, Ada.Numerics.Discrete_Random;
|
||||
-- can play human-human, human-computer, computer-human or computer-computer
|
||||
-- the computer isn't very clever: it just chooses a legal random move
|
||||
|
||||
procedure Tic_Tac_Toe is
|
||||
|
||||
type The_Range is range 1 .. 3;
|
||||
type Board_Type is array (The_Range, The_Range) of Character;
|
||||
|
||||
package Rand is new Ada.Numerics.Discrete_Random(The_Range);
|
||||
Gen: Rand.Generator; -- required for the random moves
|
||||
|
||||
procedure Show_Board(Board: Board_Type) is
|
||||
use Ada.Text_IO;
|
||||
begin
|
||||
for Row in The_Range loop
|
||||
for Column in The_Range loop
|
||||
Put(Board(Row, Column));
|
||||
end loop;
|
||||
Put_Line("");
|
||||
end loop;
|
||||
Put_Line("");
|
||||
end Show_Board;
|
||||
|
||||
function Find_Winner(Board: Board_Type) return Character is
|
||||
-- if 'x' or 'o' wins, it returns that, else it returns ' '
|
||||
|
||||
function Three_Equal(A,B,C: Character) return Boolean is
|
||||
begin
|
||||
return (A=B) and (A=C);
|
||||
end Three_Equal;
|
||||
|
||||
begin -- Find_Winner
|
||||
for I in The_Range loop
|
||||
if Three_Equal(Board(I,1), Board(I,2), Board(I,3)) then
|
||||
return Board(I,1);
|
||||
elsif Three_Equal(Board(1,I), Board(2,I), Board(3,I)) then
|
||||
return Board(1,I);
|
||||
end if;
|
||||
end loop;
|
||||
if Three_Equal(Board(1,1), Board(2,2), Board (3,3)) or
|
||||
Three_Equal(Board(3,1), Board(2,2), Board (1,3)) then
|
||||
return Board(2,2);
|
||||
end if;
|
||||
return ' ';
|
||||
end Find_Winner;
|
||||
|
||||
procedure Do_Move(Board: in out Board_Type;
|
||||
New_Char: Character; Computer_Move: Boolean) is
|
||||
Done: Boolean := False;
|
||||
C: Character;
|
||||
use Ada.Text_IO;
|
||||
|
||||
procedure Do_C_Move(Board: in out Board_Type; New_Char: Character) is
|
||||
Found: Boolean := False;
|
||||
X,Y: The_Range;
|
||||
begin
|
||||
while not Found loop
|
||||
X := Rand.Random(Gen);
|
||||
Y := Rand.Random(Gen);
|
||||
if (Board(X,Y) /= 'x') and (Board(X,Y) /= 'o') then
|
||||
Found := True;
|
||||
Board(X,Y) := New_Char;
|
||||
end if;
|
||||
end loop;
|
||||
end Do_C_Move;
|
||||
|
||||
begin
|
||||
if Computer_Move then
|
||||
Do_C_Move(Board, New_Char);
|
||||
else -- read move;
|
||||
Put_Line("Choose your move, " & New_Char);
|
||||
while not Done loop
|
||||
Get(C);
|
||||
for Row in The_Range loop
|
||||
for Col in The_Range loop
|
||||
if Board(Row, Col) = C then
|
||||
Board(Row, Col) := New_Char;
|
||||
Done := True;
|
||||
end if;
|
||||
end loop;
|
||||
end loop;
|
||||
end loop;
|
||||
end if;
|
||||
end Do_Move;
|
||||
|
||||
The_Board : Board_Type := (('1','2','3'), ('4','5','6'), ('7','8','9'));
|
||||
Cnt_Moves: Natural := 0;
|
||||
Players: array(0 .. 1) of Character := ('x', 'o'); -- 'x' begins
|
||||
C_Player: array(0 .. 1) of Boolean := (False, False);
|
||||
Reply: Character;
|
||||
|
||||
begin -- Tic_Tac_Toe
|
||||
|
||||
-- firstly, ask whether the computer shall take over either player
|
||||
for I in Players'Range loop
|
||||
Ada.Text_IO.Put_Line("Shall " & Players(I) &
|
||||
" be run by the computer? (y=yes)");
|
||||
Ada.Text_IO.Get(Reply);
|
||||
if Reply='y' or Reply='Y' then
|
||||
C_Player(I) := True;
|
||||
Ada.Text_IO.Put_Line("Yes!");
|
||||
else
|
||||
Ada.Text_IO.Put_Line("No!");
|
||||
end if;
|
||||
end loop;
|
||||
Rand.Reset(Gen); -- to initalize the random generator
|
||||
|
||||
-- now run the game
|
||||
while (Find_Winner(The_Board) = ' ') and (Cnt_Moves < 9) loop
|
||||
Show_Board(The_Board);
|
||||
Do_Move(The_Board, Players(Cnt_Moves mod 2), C_Player(Cnt_Moves mod 2));
|
||||
Cnt_Moves := Cnt_Moves + 1;
|
||||
end loop;
|
||||
Ada.Text_IO.Put_Line("This is the end!");
|
||||
|
||||
-- finally, output the outcome
|
||||
Show_Board (The_Board);
|
||||
if Find_Winner(The_Board) = ' ' then
|
||||
Ada.Text_IO.Put_Line("Draw");
|
||||
else
|
||||
Ada.Text_IO.Put_Line("The winner is: " & Find_Winner(The_Board));
|
||||
end if;
|
||||
end Tic_Tac_Toe;
|
||||
106
Task/Tic-tac-toe/AutoHotkey/tic-tac-toe.ahk
Normal file
106
Task/Tic-tac-toe/AutoHotkey/tic-tac-toe.ahk
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
Gui, Add, Button, x12 y12 w30 h30 vB1 gButtonHandler,
|
||||
Gui, Add, Button, x52 y12 w30 h30 vB2 gButtonHandler,
|
||||
Gui, Add, Button, x92 y12 w30 h30 vB3 gButtonHandler,
|
||||
Gui, Add, Button, x12 y52 w30 h30 vB4 gButtonHandler,
|
||||
Gui, Add, Button, x52 y52 w30 h30 vB5 gButtonHandler,
|
||||
Gui, Add, Button, x92 y52 w30 h30 vB6 gButtonHandler,
|
||||
Gui, Add, Button, x12 y92 w30 h30 vB7 gButtonHandler,
|
||||
Gui, Add, Button, x52 y92 w30 h30 vB8 gButtonHandler,
|
||||
Gui, Add, Button, x92 y92 w30 h30 vB9 gButtonHandler,
|
||||
; Generated using SmartGUI Creator 4.0
|
||||
Gui, Show, x127 y87 h150 w141, Tic-Tac-Toe
|
||||
Winning_Moves := "123,456,789,147,258,369,159,357"
|
||||
Return
|
||||
|
||||
ButtonHandler:
|
||||
; Fired whenever the user clicks on an enabled button
|
||||
Go(A_GuiControl,"X")
|
||||
GoSub MyMove
|
||||
Return
|
||||
|
||||
MyMove: ; Loops through winning moves. First attempts to win, then to block, then a random move
|
||||
Went=0
|
||||
Loop, parse, Winning_Moves,`,
|
||||
{
|
||||
Current_Set := A_LoopField
|
||||
X:=O:=0
|
||||
Loop, parse, Current_Set
|
||||
{
|
||||
GuiControlGet, Char,,Button%A_LoopField%
|
||||
If ( Char = "O" )
|
||||
O++
|
||||
If ( Char = "X" )
|
||||
X++
|
||||
}
|
||||
If ( O = 2 and X = 0 ) or ( X = 2 and O = 0 ){
|
||||
Finish_Line(Current_Set)
|
||||
Went = 1
|
||||
Break ; out of the Winning_Moves Loop to ensure the computer goes only once
|
||||
}
|
||||
}
|
||||
If (!Went)
|
||||
GoSub RandomMove
|
||||
Return
|
||||
|
||||
Go(Control,chr){
|
||||
GuiControl,,%Control%, %chr%
|
||||
GuiControl,Disable,%Control%
|
||||
GoSub, CheckWin
|
||||
}
|
||||
|
||||
CheckWin:
|
||||
Loop, parse, Winning_Moves,`,
|
||||
{
|
||||
Current_Set := A_LoopField
|
||||
X:=O:=0
|
||||
Loop, parse, Current_Set
|
||||
{
|
||||
GuiControlGet, Char,,Button%A_LoopField%
|
||||
If ( Char = "O" )
|
||||
O++
|
||||
If ( Char = "X" )
|
||||
X++
|
||||
}
|
||||
If ( O = 3 ){
|
||||
Msgbox O Wins!
|
||||
GoSub DisableAll
|
||||
Break
|
||||
}
|
||||
If ( X = 3 ){
|
||||
MsgBox X Wins!
|
||||
GoSub DisableAll
|
||||
Break
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
DisableAll:
|
||||
Loop, 9
|
||||
GuiControl, Disable, Button%A_Index%
|
||||
return
|
||||
|
||||
Finish_Line(Set){ ; Finish_Line is called when a line exists with 2 of the same character. It goes in the remaining spot, thereby blocking or winning.
|
||||
Loop, parse, set
|
||||
{
|
||||
GuiControlGet, IsEnabled, Enabled, Button%A_LoopField%
|
||||
Control=Button%A_LoopField%
|
||||
If IsEnabled
|
||||
Go(Control,"O")
|
||||
}
|
||||
}
|
||||
|
||||
RandomMove:
|
||||
Loop{
|
||||
Random, rnd, 1, 9
|
||||
GuiControlGet, IsEnabled, Enabled, Button%rnd%
|
||||
If IsEnabled
|
||||
{
|
||||
Control=Button%rnd%
|
||||
Go(Control,"O")
|
||||
Break
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
GuiClose:
|
||||
ExitApp
|
||||
246
Task/Tic-tac-toe/C-sharp/tic-tac-toe.cs
Normal file
246
Task/Tic-tac-toe/C-sharp/tic-tac-toe.cs
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace RosettaTicTacToe
|
||||
{
|
||||
class Program
|
||||
{
|
||||
|
||||
/*================================================================
|
||||
*Pieces (players and board)
|
||||
*================================================================*/
|
||||
static string[][] Players = new string[][] {
|
||||
new string[] { "COMPUTER", "X" }, // computer player
|
||||
new string[] { "HUMAN", "O" } // human player
|
||||
};
|
||||
|
||||
const int Unplayed = -1;
|
||||
const int Computer = 0;
|
||||
const int Human = 1;
|
||||
|
||||
// GameBoard holds index into Players[] (0 or 1) or Unplayed (-1) if location not yet taken
|
||||
static int[] GameBoard = new int[9];
|
||||
|
||||
static int[] corners = new int[] { 0, 2, 6, 8 };
|
||||
|
||||
static int[][] wins = new int[][] {
|
||||
new int[] { 0, 1, 2 }, new int[] { 3, 4, 5 }, new int[] { 6, 7, 8 },
|
||||
new int[] { 0, 3, 6 }, new int[] { 1, 4, 7 }, new int[] { 2, 5, 8 },
|
||||
new int[] { 0, 4, 8 }, new int[] { 2, 4, 6 } };
|
||||
|
||||
|
||||
/*================================================================
|
||||
*Main Game Loop (this is what runs/controls the game)
|
||||
*================================================================*/
|
||||
static void Main(string[] args)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Console.Clear();
|
||||
Console.WriteLine("Welcome to Rosetta Code Tic-Tac-Toe for C#.");
|
||||
initializeGameBoard();
|
||||
displayGameBoard();
|
||||
int currentPlayer = rnd.Next(0, 2); // current player represented by Players[] index of 0 or 1
|
||||
Console.WriteLine("The first move goes to {0} who is playing {1}s.\n", playerName(currentPlayer), playerToken(currentPlayer));
|
||||
while (true)
|
||||
{
|
||||
int thisMove = getMoveFor(currentPlayer);
|
||||
if (thisMove == Unplayed)
|
||||
{
|
||||
Console.WriteLine("{0}, you've quit the game ... am I that good?", playerName(currentPlayer));
|
||||
break;
|
||||
}
|
||||
playMove(thisMove, currentPlayer);
|
||||
displayGameBoard();
|
||||
if (isGameWon())
|
||||
{
|
||||
Console.WriteLine("{0} has won the game!", playerName(currentPlayer));
|
||||
break;
|
||||
}
|
||||
else if (isGameTied())
|
||||
{
|
||||
Console.WriteLine("Cat game ... we have a tie.");
|
||||
break;
|
||||
}
|
||||
currentPlayer = getNextPlayer(currentPlayer);
|
||||
}
|
||||
if (!playAgain())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*================================================================
|
||||
*Move Logic
|
||||
*================================================================*/
|
||||
static int getMoveFor(int player)
|
||||
{
|
||||
if (player == Human)
|
||||
return getManualMove(player);
|
||||
else
|
||||
{
|
||||
//int selectedMove = getManualMove(player);
|
||||
//int selectedMove = getRandomMove(player);
|
||||
int selectedMove = getSemiRandomMove(player);
|
||||
//int selectedMove = getBestMove(player);
|
||||
Console.WriteLine("{0} selects position {1}.", playerName(player), selectedMove + 1);
|
||||
return selectedMove;
|
||||
}
|
||||
}
|
||||
|
||||
static int getManualMove(int player)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Console.Write("{0}, enter you move (number): ", playerName(player));
|
||||
ConsoleKeyInfo keyInfo = Console.ReadKey();
|
||||
Console.WriteLine(); // keep the display pretty
|
||||
if (keyInfo.Key == ConsoleKey.Escape)
|
||||
return Unplayed;
|
||||
if (keyInfo.Key >= ConsoleKey.D1 && keyInfo.Key <= ConsoleKey.D9)
|
||||
{
|
||||
int move = keyInfo.KeyChar - '1'; // convert to between 0..8, a GameBoard index position.
|
||||
if (GameBoard[move] == Unplayed)
|
||||
return move;
|
||||
else
|
||||
Console.WriteLine("Spot {0} is already taken, please select again.", move + 1);
|
||||
}
|
||||
else
|
||||
Console.WriteLine("Illegal move, please select again.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int getRandomMove(int player)
|
||||
{
|
||||
int movesLeft = GameBoard.Count(position => position == Unplayed);
|
||||
int x = rnd.Next(0, movesLeft);
|
||||
for (int i = 0; i < GameBoard.Length; i++) // walk board ...
|
||||
{
|
||||
if (GameBoard[i] == Unplayed && x < 0) // until we reach the unplayed move.
|
||||
return i;
|
||||
x--;
|
||||
}
|
||||
return Unplayed;
|
||||
}
|
||||
|
||||
// plays random if no winning move or needed block.
|
||||
static int getSemiRandomMove(int player)
|
||||
{
|
||||
int posToPlay;
|
||||
if (checkForWinningMove(player, out posToPlay))
|
||||
return posToPlay;
|
||||
if (checkForBlockingMove(player, out posToPlay))
|
||||
return posToPlay;
|
||||
return getRandomMove(player);
|
||||
}
|
||||
|
||||
// purposely not implemented (this is the thinking part).
|
||||
static int getBestMove(int player)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool checkForWinningMove(int player, out int posToPlay)
|
||||
{
|
||||
posToPlay = Unplayed;
|
||||
foreach (var line in wins)
|
||||
if (twoOfThreeMatchPlayer(player, line, out posToPlay))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkForBlockingMove(int player, out int posToPlay)
|
||||
{
|
||||
posToPlay = Unplayed;
|
||||
foreach (var line in wins)
|
||||
if (twoOfThreeMatchPlayer(getNextPlayer(player), line, out posToPlay))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool twoOfThreeMatchPlayer(int player, int[] line, out int posToPlay)
|
||||
{
|
||||
int cnt = 0;
|
||||
posToPlay = int.MinValue;
|
||||
foreach (int pos in line)
|
||||
{
|
||||
if (GameBoard[pos] == player)
|
||||
cnt++;
|
||||
else if (GameBoard[pos] == Unplayed)
|
||||
posToPlay = pos;
|
||||
}
|
||||
return cnt == 2 && posToPlay >= 0;
|
||||
}
|
||||
|
||||
static void playMove(int boardPosition, int player)
|
||||
{
|
||||
GameBoard[boardPosition] = player;
|
||||
}
|
||||
|
||||
static bool isGameWon()
|
||||
{
|
||||
return wins.Any(line => takenBySamePlayer(line[0], line[1], line[2]));
|
||||
}
|
||||
|
||||
static bool takenBySamePlayer(int a, int b, int c)
|
||||
{
|
||||
return GameBoard[a] != Unplayed && GameBoard[a] == GameBoard[b] && GameBoard[a] == GameBoard[c];
|
||||
}
|
||||
|
||||
static bool isGameTied()
|
||||
{
|
||||
return !GameBoard.Any(spot => spot == Unplayed);
|
||||
}
|
||||
|
||||
/*================================================================
|
||||
*Misc Methods
|
||||
*================================================================*/
|
||||
static Random rnd = new Random();
|
||||
|
||||
static void initializeGameBoard()
|
||||
{
|
||||
for (int i = 0; i < GameBoard.Length; i++)
|
||||
GameBoard[i] = Unplayed;
|
||||
}
|
||||
|
||||
static string playerName(int player)
|
||||
{
|
||||
return Players[player][0];
|
||||
}
|
||||
|
||||
static string playerToken(int player)
|
||||
{
|
||||
return Players[player][1];
|
||||
}
|
||||
|
||||
static int getNextPlayer(int player)
|
||||
{
|
||||
return (player + 1) % 2;
|
||||
}
|
||||
|
||||
static void displayGameBoard()
|
||||
{
|
||||
Console.WriteLine(" {0} | {1} | {2}", pieceAt(0), pieceAt(1), pieceAt(2));
|
||||
Console.WriteLine("---|---|---");
|
||||
Console.WriteLine(" {0} | {1} | {2}", pieceAt(3), pieceAt(4), pieceAt(5));
|
||||
Console.WriteLine("---|---|---");
|
||||
Console.WriteLine(" {0} | {1} | {2}", pieceAt(6), pieceAt(7), pieceAt(8));
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
static string pieceAt(int boardPosition)
|
||||
{
|
||||
if (GameBoard[boardPosition] == Unplayed)
|
||||
return (boardPosition + 1).ToString(); // display 1..9 on board rather than 0..8
|
||||
return playerToken(GameBoard[boardPosition]);
|
||||
}
|
||||
|
||||
private static bool playAgain()
|
||||
{
|
||||
Console.WriteLine("\nDo you want to play again?");
|
||||
return Console.ReadKey(false).Key == ConsoleKey.Y;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
103
Task/Tic-tac-toe/C/tic-tac-toe.c
Normal file
103
Task/Tic-tac-toe/C/tic-tac-toe.c
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int b[3][3]; /* board. 0: blank; -1: computer; 1: human */
|
||||
|
||||
int check_winner()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (b[i][0] && b[i][1] == b[i][0] && b[i][2] == b[i][0])
|
||||
return b[i][0];
|
||||
if (b[0][i] && b[1][i] == b[0][i] && b[2][i] == b[0][i])
|
||||
return b[0][i];
|
||||
}
|
||||
if (!b[1][1]) 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;
|
||||
}
|
||||
|
||||
void showboard()
|
||||
{
|
||||
const char *t = "X O";
|
||||
int i, j;
|
||||
for (i = 0; i < 3; i++, putchar('\n'))
|
||||
for (j = 0; j < 3; j++)
|
||||
printf("%c ", t[ b[i][j] + 1 ]);
|
||||
printf("-----\n");
|
||||
}
|
||||
|
||||
#define for_ij for (i = 0; i < 3; i++) for (j = 0; j < 3; j++)
|
||||
int best_i, best_j;
|
||||
int test_move(int val, int depth)
|
||||
{
|
||||
int i, j, score;
|
||||
int best = -1, changed = 0;
|
||||
|
||||
if ((score = check_winner())) return (score == val) ? 1 : -1;
|
||||
|
||||
for_ij {
|
||||
if (b[i][j]) continue;
|
||||
|
||||
changed = b[i][j] = val;
|
||||
score = -test_move(-val, depth + 1);
|
||||
b[i][j] = 0;
|
||||
|
||||
if (score <= best) continue;
|
||||
if (!depth) {
|
||||
best_i = i;
|
||||
best_j = j;
|
||||
}
|
||||
best = score;
|
||||
}
|
||||
|
||||
return changed ? best : 0;
|
||||
}
|
||||
|
||||
const char* game(int user)
|
||||
{
|
||||
int i, j, k, move, win = 0;
|
||||
for_ij b[i][j] = 0;
|
||||
|
||||
printf("Board postions are numbered so:\n1 2 3\n4 5 6\n7 8 9\n");
|
||||
printf("You have O, I have X.\n\n");
|
||||
for (k = 0; k < 9; k++, user = !user) {
|
||||
while(user) {
|
||||
printf("your move: ");
|
||||
if (!scanf("%d", &move)) {
|
||||
scanf("%*s");
|
||||
continue;
|
||||
}
|
||||
if (--move < 0 || move >= 9) continue;
|
||||
if (b[i = move / 3][j = move % 3]) continue;
|
||||
|
||||
b[i][j] = 1;
|
||||
break;
|
||||
}
|
||||
if (!user) {
|
||||
if (!k) { /* randomize if computer opens, less boring */
|
||||
best_i = rand() % 3;
|
||||
best_j = rand() % 3;
|
||||
} else
|
||||
test_move(-1, 0);
|
||||
|
||||
b[best_i][best_j] = -1;
|
||||
printf("My move: %d\n", best_i * 3 + best_j + 1);
|
||||
}
|
||||
|
||||
showboard();
|
||||
if ((win = check_winner()))
|
||||
return win == 1 ? "You win.\n\n": "I win.\n\n";
|
||||
}
|
||||
return "A draw.\n\n";
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int first = 0;
|
||||
while (1) printf("%s", game(first = !first));
|
||||
return 0;
|
||||
}
|
||||
120
Task/Tic-tac-toe/D/tic-tac-toe.d
Normal file
120
Task/Tic-tac-toe/D/tic-tac-toe.d
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
import std.stdio, std.string, std.algorithm, std.conv,
|
||||
std.random, std.ascii, std.array, std.range;
|
||||
|
||||
struct GameBoard {
|
||||
dchar[9] board = "123456789";
|
||||
enum : char { human = 'X', computer = 'O' }
|
||||
enum Game { going, humanWins, computerWins, draw }
|
||||
|
||||
const pure nothrow invariant() {
|
||||
foreach (i, c; board)
|
||||
if (isDigit(c))
|
||||
assert(i == c - '1'); // in correct position?
|
||||
else
|
||||
assert(c == human || c == computer);
|
||||
}
|
||||
|
||||
string toString() const {
|
||||
return xformat("%(%-(%s|%)\n-+-+-\n%)",
|
||||
std.range.chunks(board.dup, 3));
|
||||
}
|
||||
|
||||
bool isAvailable(in int i) const pure nothrow {
|
||||
if (i < 0 || i >= 9)
|
||||
return false;
|
||||
return isDigit(board[i]);
|
||||
}
|
||||
|
||||
int[] availablePositions() const pure nothrow {
|
||||
// not pure not nothrow:
|
||||
//return iota(9).filter!(i => isDigit(board[i]))().array();
|
||||
int[] result;
|
||||
foreach (i; 0 .. 9)
|
||||
if (isAvailable(i))
|
||||
result ~= i;
|
||||
return result;
|
||||
}
|
||||
|
||||
Game winner() const pure nothrow {
|
||||
immutable wins = [[0, 1, 2], [3, 4, 5], [6, 7, 8],
|
||||
[0, 3, 6], [1, 4, 7], [2, 5, 8],
|
||||
[0, 4, 8], [2, 4, 6]];
|
||||
|
||||
foreach (const win; wins) {
|
||||
immutable bw0 = board[win[0]];
|
||||
if (isDigit(bw0))
|
||||
continue; // nobody wins on this one
|
||||
|
||||
if (bw0 == board[win[1]] && bw0 == board[win[2]])
|
||||
return bw0 == GameBoard.human ?
|
||||
Game.humanWins :
|
||||
Game.computerWins;
|
||||
}
|
||||
|
||||
return availablePositions().empty ? Game.draw: Game.going;
|
||||
}
|
||||
|
||||
bool finished() const pure nothrow {
|
||||
return winner() != Game.going;
|
||||
}
|
||||
|
||||
int computerMove() const // random move
|
||||
out(res) {
|
||||
assert(res >= 0 && res < 9 && isAvailable(res));
|
||||
} body {
|
||||
// return choice(availablePositions());
|
||||
return randomCover(availablePositions(), rndGen).front;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GameBoard playGame() {
|
||||
GameBoard board;
|
||||
bool playsHuman = true;
|
||||
|
||||
while (!board.finished()) {
|
||||
writeln(board);
|
||||
|
||||
int move;
|
||||
if (playsHuman) {
|
||||
do {
|
||||
writef("Your move (available moves: %s)? ",
|
||||
board.availablePositions().map!q{ a + 1 }());
|
||||
readf("%d\n", &move);
|
||||
move--; // zero based indexing
|
||||
if (move < 0)
|
||||
return board;
|
||||
} while (!board.isAvailable(move));
|
||||
} else
|
||||
move = board.computerMove();
|
||||
|
||||
assert(board.isAvailable(move));
|
||||
writefln("\n%s chose %d", playsHuman ? "You" : "I", move + 1);
|
||||
board.board[move] = playsHuman ? GameBoard.human :
|
||||
GameBoard.computer;
|
||||
playsHuman = !playsHuman; // switch player
|
||||
}
|
||||
|
||||
return board;
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
writeln("Tic-tac-toe game player.\n");
|
||||
immutable outcome = playGame().winner();
|
||||
|
||||
final switch (outcome) {
|
||||
case GameBoard.Game.going:
|
||||
writeln("Game stopped.");
|
||||
break;
|
||||
case GameBoard.Game.humanWins:
|
||||
writeln("\nYou win!");
|
||||
break;
|
||||
case GameBoard.Game.computerWins:
|
||||
writeln("\nI win.");
|
||||
break;
|
||||
case GameBoard.Game.draw:
|
||||
writeln("\nDraw");
|
||||
break;
|
||||
}
|
||||
}
|
||||
160
Task/Tic-tac-toe/Go/tic-tac-toe.go
Normal file
160
Task/Tic-tac-toe/Go/tic-tac-toe.go
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var b []byte
|
||||
|
||||
func printBoard() {
|
||||
fmt.Printf("%s\n%s\n%s\n", b[0:3], b[3:6], b[6:9])
|
||||
}
|
||||
|
||||
var pScore, cScore int
|
||||
var pMark, cMark byte = 'X', 'O'
|
||||
var in = bufio.NewReader(os.Stdin)
|
||||
|
||||
func main() {
|
||||
b = make([]byte, 9)
|
||||
fmt.Println("Play by entering a digit.")
|
||||
for {
|
||||
// start of game
|
||||
for i := range b {
|
||||
b[i] = '1' + byte(i)
|
||||
}
|
||||
computerStart := cMark == 'X'
|
||||
if computerStart {
|
||||
fmt.Println("I go first, playing X's")
|
||||
} else {
|
||||
fmt.Println("You go first, playing X's")
|
||||
}
|
||||
TakeTurns:
|
||||
for {
|
||||
if !computerStart {
|
||||
if !playerTurn() {
|
||||
return
|
||||
}
|
||||
if gameOver() {
|
||||
break TakeTurns
|
||||
}
|
||||
|
||||
}
|
||||
computerStart = false
|
||||
computerTurn()
|
||||
if gameOver() {
|
||||
break TakeTurns
|
||||
}
|
||||
}
|
||||
fmt.Println("Score: you", pScore, "me", cScore)
|
||||
fmt.Println("\nLet's play again.")
|
||||
}
|
||||
}
|
||||
|
||||
func playerTurn() bool {
|
||||
var pm string
|
||||
var err error
|
||||
for i := 0; i < 3; i++ { // retry loop
|
||||
printBoard()
|
||||
fmt.Printf("%c's move? ", pMark)
|
||||
if pm, err = in.ReadString('\n'); err != nil {
|
||||
fmt.Println(err)
|
||||
return false
|
||||
}
|
||||
pm = strings.TrimSpace(pm)
|
||||
if pm >= "1" && pm <= "9" && b[pm[0]-'1'] == pm[0] {
|
||||
x := pm[0] - '1'
|
||||
b[x] = pMark
|
||||
return true
|
||||
}
|
||||
}
|
||||
fmt.Println("You're not playing right.")
|
||||
return false
|
||||
}
|
||||
|
||||
var choices = make([]int, 9)
|
||||
|
||||
func computerTurn() {
|
||||
printBoard()
|
||||
var x int
|
||||
defer func() {
|
||||
fmt.Println("My move:", x+1)
|
||||
b[x] = cMark
|
||||
}()
|
||||
// look for two in a row
|
||||
block := -1
|
||||
for _, l := range lines {
|
||||
var mine, yours int
|
||||
x = -1
|
||||
for _, sq := range l {
|
||||
switch b[sq] {
|
||||
case cMark:
|
||||
mine++
|
||||
case pMark:
|
||||
yours++
|
||||
default:
|
||||
x = sq
|
||||
}
|
||||
}
|
||||
if mine == 2 && x >= 0 {
|
||||
return // strategy 1: make winning move
|
||||
}
|
||||
if yours == 2 && x >= 0 {
|
||||
block = x
|
||||
}
|
||||
}
|
||||
if block >= 0 {
|
||||
x = block // strategy 2: make blocking move
|
||||
return
|
||||
}
|
||||
// default strategy: random move
|
||||
choices = choices[:0]
|
||||
for i, sq := range b {
|
||||
if sq == '1'+byte(i) {
|
||||
choices = append(choices, i)
|
||||
}
|
||||
}
|
||||
x = choices[rand.Intn(len(choices))]
|
||||
}
|
||||
|
||||
func gameOver() bool {
|
||||
// check for win
|
||||
for _, l := range lines {
|
||||
if b[l[0]] == b[l[1]] && b[l[1]] == b[l[2]] {
|
||||
printBoard()
|
||||
if b[l[0]] == cMark {
|
||||
fmt.Println("I win!")
|
||||
cScore++
|
||||
pMark, cMark = 'X', 'O'
|
||||
} else {
|
||||
fmt.Println("You win!")
|
||||
pScore++
|
||||
pMark, cMark = 'O', 'X'
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
// check for empty squares
|
||||
for i, sq := range b {
|
||||
if sq == '1'+byte(i) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
fmt.Println("Cat game.")
|
||||
pMark, cMark = cMark, pMark
|
||||
return true
|
||||
}
|
||||
|
||||
var lines = [][]int{
|
||||
{0, 1, 2}, // rows
|
||||
{3, 4, 5},
|
||||
{6, 7, 8},
|
||||
{0, 3, 6}, // columns
|
||||
{1, 4, 7},
|
||||
{2, 5, 8},
|
||||
{0, 4, 8}, // diagonals
|
||||
{2, 4, 6},
|
||||
}
|
||||
134
Task/Tic-tac-toe/Groovy/tic-tac-toe.groovy
Normal file
134
Task/Tic-tac-toe/Groovy/tic-tac-toe.groovy
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
class Main {
|
||||
|
||||
def input = new Scanner(System.in)
|
||||
|
||||
static main(args) {
|
||||
Main main = new Main();
|
||||
main.play();
|
||||
}
|
||||
|
||||
public void play() {
|
||||
|
||||
TicTackToe game = new TicTackToe();
|
||||
game.init()
|
||||
def gameOver = false
|
||||
def player = game.player1
|
||||
|
||||
println "Players take turns marking a square. Only squares \n"+
|
||||
"not already marked can be picked. Once a player has \n"+
|
||||
"marked three squares in a row, column or diagonal, they win! If all squares \n"+
|
||||
"are marked and no three squares are the same, a tied game is declared.\n"+
|
||||
"Player 1 is O and Player 2 is X \n"+
|
||||
"Have Fun! \n\n"
|
||||
println "${game.drawBoard()}"
|
||||
|
||||
while (!gameOver && game.plays < 9) {
|
||||
|
||||
player = game.currentPlayer == 1 ? game.player1 :game.player2
|
||||
def validPick = false;
|
||||
while (!validPick) {
|
||||
|
||||
def square
|
||||
println "Next $player, enter move by selecting square's number :"
|
||||
try {
|
||||
square = input.nextLine();
|
||||
} catch (Exception ex) { }
|
||||
|
||||
if (square.length() == 1 && Character.isDigit(square.toCharArray()[0])) { validPick = game.placeMarker(square) }
|
||||
if (!validPick) { println "Select another Square" }
|
||||
|
||||
}
|
||||
|
||||
(game.checkWinner(player))? gameOver = true : game.switchPlayers()
|
||||
println(game.drawBoard());
|
||||
|
||||
}
|
||||
println "Game Over, " + ((gameOver == true)? "$player Wins" : "Draw")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TicTackToe {
|
||||
|
||||
def board = new Object[3][3]
|
||||
def final player1 = "player 1"
|
||||
def final player2 = "player 2"
|
||||
def final marker1 = 'X'
|
||||
def final marker2 = 'O'
|
||||
|
||||
int currentPlayer
|
||||
int plays
|
||||
|
||||
public TicTacToe(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
def init() {
|
||||
int counter = 0;
|
||||
(0..2).each { row ->
|
||||
(0..2).each { col ->
|
||||
board[row][col] = (++counter).toString();
|
||||
}
|
||||
}
|
||||
plays = 0
|
||||
currentPlayer =1
|
||||
}
|
||||
|
||||
def switchPlayers() {
|
||||
currentPlayer = (currentPlayer == 1) ? 2:1
|
||||
plays++
|
||||
}
|
||||
|
||||
def placeMarker(play) {
|
||||
def result = false
|
||||
(0..2).each { row ->
|
||||
(0..2).each { col ->
|
||||
if (board[row][col].toString()==play.toString()){
|
||||
board[row][col] = (currentPlayer == 1) ? marker2 : marker1;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
def checkWinner(player) {
|
||||
char current = (player == player1)? marker2: marker1
|
||||
//Checking
|
||||
return checkRows(current) || checkColumns(current) ||checkDiagonals(current);
|
||||
}
|
||||
|
||||
def checkRows(char current){
|
||||
(0..2).any{ line ->
|
||||
board[line].every { it == current}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def checkColumns(char current){
|
||||
(0..2).any{i ->
|
||||
(0..2).every{j ->
|
||||
board[j][i]==current }
|
||||
}
|
||||
}
|
||||
|
||||
def checkDiagonals(char current){
|
||||
def rightDiag = [board[0][0],board[1][1],board[2][2]]
|
||||
def leftDiag = [board[0][2],board[1][1],board[2][0]]
|
||||
return rightDiag.every{it == current} || leftDiag.every{it == current}
|
||||
}
|
||||
|
||||
|
||||
def drawBoard() {
|
||||
StringBuilder builder = new StringBuilder("Game board: \n");
|
||||
(0..2).each { row->
|
||||
(0..2).each {col ->
|
||||
builder.append("[" + board[row][col] + "]");
|
||||
}
|
||||
builder.append("\n");
|
||||
}
|
||||
builder.append("\n");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
220
Task/Tic-tac-toe/Haskell/tic-tac-toe.hs
Normal file
220
Task/Tic-tac-toe/Haskell/tic-tac-toe.hs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
module Main where
|
||||
|
||||
import System.Random
|
||||
import Data.List (intercalate, find, minimumBy)
|
||||
import System.Environment (getArgs)
|
||||
import Data.Char (digitToInt)
|
||||
import Data.Maybe (listToMaybe, mapMaybe)
|
||||
import Control.Monad (guard)
|
||||
import Data.Ord (comparing)
|
||||
|
||||
-- check if there is a horizontal, vertical or diagonal line of
|
||||
-- X or O
|
||||
tictactoe :: String -> Bool
|
||||
tictactoe a = tictactoeFor 'X' a /= tictactoeFor 'O' a
|
||||
|
||||
-- check if there is a horizontal, vertical or diagonal line
|
||||
-- for the given player "n"
|
||||
tictactoeFor :: Char -> String -> Bool
|
||||
tictactoeFor n [a,b,c,d,e,f,g,h,i] =
|
||||
[n,n,n] `elem` [[a,b,c],[d,e,f],[g,h,i],[a,d,g],
|
||||
[b,e,h],[c,f,i],[a,e,i],[c,e,g]]
|
||||
|
||||
-- empty game board
|
||||
start :: String
|
||||
start = " "
|
||||
|
||||
-- check if there is an X or an O at the given position
|
||||
isPossible :: Int -> String -> Bool
|
||||
isPossible n game = (game !! n) `notElem` "XO"
|
||||
|
||||
-- try to place an X or an O at a given position.
|
||||
-- "Right" + modified board means success, "Left" + unmodified board
|
||||
-- means failure
|
||||
place :: Int -> Char -> String -> Either String String
|
||||
place i c game =
|
||||
if isPossible i game
|
||||
then Right $ take i game ++ [c] ++ drop (i + 1) game
|
||||
else Left game
|
||||
|
||||
-- COMPUTER AI
|
||||
-- get the number of movements, starting from a given non-empty board
|
||||
-- and a position for the next movement, until the specified player
|
||||
-- wins or no movement is possible
|
||||
-- the positions are chosen sequentially, so there's not much
|
||||
-- intelligence here anyway
|
||||
developGame :: Bool -> Int -> Int -> Char -> String -> (Int, Char, String)
|
||||
developGame iterateMore moves i player game
|
||||
| i > 8 =
|
||||
-- if i arrives to the last position, iterate again from 0
|
||||
-- but do it only once
|
||||
if iterateMore
|
||||
then developGame False moves 0 player game
|
||||
-- draw game (after one iteration, still no winning moves)
|
||||
else (moves, player, game)
|
||||
-- draw game (game board full) or a win for the player
|
||||
| moves == 9 || tictactoeFor player game = (moves, player, game)
|
||||
-- make a move, if possible, and continue playing
|
||||
| otherwise = case place i otherPlayer game of
|
||||
-- position i is not empty. try with the next position
|
||||
Left _ -> developGame iterateMore moves (i + 1)
|
||||
otherPlayer game
|
||||
-- position i was empty, so it was a valid move.
|
||||
-- change the player and make a new move, starting at pos 0
|
||||
Right newGame -> developGame iterateMore (moves + 1) 0
|
||||
otherPlayer newGame
|
||||
where
|
||||
otherPlayer = changePlayer player
|
||||
|
||||
-- COMPUTER AI
|
||||
-- starting from a given non-empty board, try to guess which position
|
||||
-- could lead the player to the fastest victory.
|
||||
bestMoveFor :: Char -> String -> Int
|
||||
bestMoveFor player game = bestMove
|
||||
where
|
||||
-- drive the game to its end for each starting position
|
||||
continuations = [ (x, developGame True 0 x player game) |
|
||||
x <- [0..8] ]
|
||||
-- compare the number of moves of the game and take the
|
||||
-- shortest one
|
||||
move (_, (m, _, _)) = m
|
||||
(bestMove, _) = minimumBy (comparing move) continuations
|
||||
|
||||
-- canBlock checks if the opponent has two pieces in a row and the
|
||||
-- other cell in the row is empty, and places the player's piece there,
|
||||
-- blocking the opponent
|
||||
canBlock :: Char -> String -> Maybe Int
|
||||
canBlock p [a,b,c,d,e,f,g,h,i] =
|
||||
listToMaybe $ mapMaybe blockable [[a,b,c],[d,e,f],[g,h,i],[a,d,g],
|
||||
[b,e,h],[c,f,i],[a,e,i],[c,e,g]]
|
||||
where
|
||||
blockable xs = do
|
||||
guard $ length (filter (== otherPlayer) xs) == 2
|
||||
x <- find (`elem` "123456789") xs
|
||||
return $ digitToInt x
|
||||
otherPlayer = changePlayer p
|
||||
|
||||
-- format a game board for on-screen printing
|
||||
showGame :: String -> String
|
||||
showGame [a,b,c,d,e,f,g,h,i] =
|
||||
topBottom ++
|
||||
"| | 1 | 2 | 3 |\n" ++
|
||||
topBottom ++
|
||||
row "0" [[a],[b],[c]] ++
|
||||
row "3" [[d],[e],[f]] ++
|
||||
row "6" [[g],[h],[i]]
|
||||
where
|
||||
topBottom = "+----+---+---+---+\n"
|
||||
row n x = "| " ++ n ++ "+ | " ++
|
||||
intercalate " | " x ++ " |\n" ++ topBottom
|
||||
|
||||
-- ask the user to press a numeric key and convert it to an int
|
||||
enterNumber :: IO Int
|
||||
enterNumber = do
|
||||
c <- getChar
|
||||
if c `elem` "123456789"
|
||||
then do
|
||||
putStrLn ""
|
||||
return $ digitToInt c
|
||||
else do
|
||||
putStrLn "\nPlease enter a digit!"
|
||||
enterNumber
|
||||
|
||||
-- a human player's turn: get the number of pieces put on the board,
|
||||
-- the next piece to be put (X or O) and a game board, and return
|
||||
-- a new game state, checking if the piece can be placed on the board.
|
||||
-- if it can't, make the user try again.
|
||||
turn :: (Int, Char, String) -> IO (Int, Char, String)
|
||||
turn (count, player, game) = do
|
||||
putStr $ "Please tell me where you want to put an " ++
|
||||
[player] ++ ": "
|
||||
pos <- enterNumber
|
||||
case place (pos - 1) player game of
|
||||
Left oldGame -> do
|
||||
putStrLn "That place is already taken!\n"
|
||||
turn (count, player, oldGame)
|
||||
Right newGame ->
|
||||
return (count + 1, changePlayer player, newGame)
|
||||
|
||||
-- alternate between X and O players
|
||||
changePlayer :: Char -> Char
|
||||
changePlayer 'O' = 'X'
|
||||
changePlayer 'X' = 'O'
|
||||
|
||||
-- COMPUTER AI
|
||||
-- make an automatic turn, placing an X or an O game board.
|
||||
-- the first movement is always random.
|
||||
-- first, the computer looks for two pieces of his opponent in a row
|
||||
-- and tries to block.
|
||||
-- otherwise, it tries to guess the best position for the next movement.
|
||||
-- as a least ressource, it places a piece randomly.
|
||||
autoTurn :: Bool -> (Int, Char, String) -> IO (Int, Char, String)
|
||||
autoTurn forceRandom (count, player, game) = do
|
||||
-- try a random position 'cause everything else failed
|
||||
-- count == 0 overrides the value of forceRandom
|
||||
i <- if count == 0 || forceRandom
|
||||
then randomRIO (0,8)
|
||||
else return $
|
||||
case canBlock player game of
|
||||
-- opponent can't be blocked. try to guess
|
||||
-- the best movement
|
||||
Nothing -> bestMoveFor player game
|
||||
-- opponent can be blocked, so just do it!
|
||||
Just blockPos -> blockPos
|
||||
-- if trying to place a piece at a calculated position doesn't work,
|
||||
-- just try again with a random value
|
||||
case place i player game of
|
||||
Left oldGame -> autoTurn True (count, player, oldGame)
|
||||
Right newGame -> do
|
||||
putStrLn $ "It's player " ++ [player] ++ "'s turn."
|
||||
return (count + 1, changePlayer player, newGame)
|
||||
|
||||
-- play a game until someone wins or the board becomes full.
|
||||
-- depending on the value of the variable "auto", ask the user(s) to
|
||||
-- put some pieces on the board or do it automatically
|
||||
play :: Int -> (Int, Char, String) -> IO ()
|
||||
play auto cpg@(_, player, game) = do
|
||||
newcpg@(newCount, newPlayer, newGame) <- case auto of
|
||||
-- if both players are human, always ask them
|
||||
0 -> turn cpg
|
||||
-- if both players are computer, always play auto
|
||||
1 -> autoTurn False cpg
|
||||
-- X is computer, O is human
|
||||
2 -> if player == 'X' then autoTurn False cpg else turn cpg
|
||||
-- X is human, O is computer
|
||||
3 -> if player == 'O' then autoTurn False cpg else turn cpg
|
||||
putStrLn $ "\n" ++ showGame newGame
|
||||
if tictactoe newGame
|
||||
then putStrLn $ "Player " ++ [changePlayer newPlayer] ++ " wins!\n"
|
||||
else
|
||||
if newCount == 9
|
||||
then putStrLn "Draw!\n"
|
||||
else play auto newcpg
|
||||
|
||||
-- main program: greet the user, ask for a game type, ask for the
|
||||
-- player that'll start the game, and play the game beginning with an
|
||||
-- empty board
|
||||
main :: IO ()
|
||||
main = do
|
||||
a <- getArgs
|
||||
if null a
|
||||
then usage
|
||||
else do
|
||||
let option = head a
|
||||
if option `elem` ["0","1","2","3"]
|
||||
then do
|
||||
putStrLn $ "\n" ++ showGame start
|
||||
let m = read option :: Int
|
||||
play m (0, 'X', start)
|
||||
else usage
|
||||
|
||||
usage :: IO ()
|
||||
usage = do
|
||||
putStrLn "TIC-TAC-TOE GAME\n================\n"
|
||||
putStrLn "How do you want to play?"
|
||||
putStrLn "Run the program with one of the following options."
|
||||
putStrLn "0 : both players are human"
|
||||
putStrLn "1 : both players are computer"
|
||||
putStrLn "2 : player X is computer and player O is human"
|
||||
putStrLn "3 : player X is human and player O is computer"
|
||||
putStrLn "Player X always begins."
|
||||
112
Task/Tic-tac-toe/Icon/tic-tac-toe.icon
Normal file
112
Task/Tic-tac-toe/Icon/tic-tac-toe.icon
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# Play TicTacToe
|
||||
|
||||
$define E " " # empty square
|
||||
$define X "X" # X piece
|
||||
$define O "O" # O piece
|
||||
|
||||
# -- define a board
|
||||
record Board(a, b, c, d, e, f, g, h, i)
|
||||
|
||||
procedure display_board (board, player)
|
||||
write ("\n===============")
|
||||
write (board.a || " | " || board.b || " | " || board.c)
|
||||
write ("---------")
|
||||
write (board.d || " | " || board.e || " | " || board.f)
|
||||
write ("---------")
|
||||
write (board.g || " | " || board.h || " | " || board.i)
|
||||
end
|
||||
|
||||
# return a set of valid moves (empty positions) in given board
|
||||
procedure empty_fields (board)
|
||||
fields := set()
|
||||
every i := !fieldnames(board) do
|
||||
if (board[i] == E) then insert (fields, i)
|
||||
return fields
|
||||
end
|
||||
|
||||
procedure game_start ()
|
||||
return Board (E, E, E, E, E, E, E, E, E)
|
||||
end
|
||||
|
||||
procedure game_is_drawn (board)
|
||||
return *empty_fields(board) = 0
|
||||
end
|
||||
|
||||
procedure game_won_by (board, player)
|
||||
return (board.a == board.b == board.c == player) |
|
||||
(board.d == board.e == board.f == player) |
|
||||
(board.g == board.h == board.i == player) |
|
||||
(board.a == board.d == board.g == player) |
|
||||
(board.b == board.e == board.h == player) |
|
||||
(board.c == board.f == board.i == player) |
|
||||
(board.a == board.e == board.i == player) |
|
||||
(board.g == board.e == board.c == player)
|
||||
end
|
||||
|
||||
procedure game_over (board)
|
||||
return game_is_drawn (board) | game_won_by (board, O) | game_won_by (board, X)
|
||||
end
|
||||
|
||||
# -- players make their move on the board
|
||||
# assume there is at least one empty square
|
||||
|
||||
procedure human_move (board, player)
|
||||
choice := "z"
|
||||
options := empty_fields (board)
|
||||
# keep prompting until player selects a valid square
|
||||
until member (options, choice) do {
|
||||
writes ("Choose one of: ")
|
||||
every writes (!options || " ")
|
||||
writes ("\n> ")
|
||||
choice := read ()
|
||||
}
|
||||
board[choice] := player
|
||||
end
|
||||
|
||||
# pick and make a move at random from empty positions
|
||||
procedure random_move (board, player)
|
||||
board[?empty_fields(board)] := player
|
||||
end
|
||||
|
||||
# -- manage the game play
|
||||
procedure play_game ()
|
||||
# hold procedures for players' move in variables
|
||||
player_O := random_move
|
||||
player_X := human_move
|
||||
|
||||
# randomly determine if human or computer moves first
|
||||
if (?2 = 0)
|
||||
then {
|
||||
write ("Human plays first as O")
|
||||
player_O := human_move
|
||||
player_X := random_move
|
||||
}
|
||||
else write ("Computer plays first, human is X")
|
||||
|
||||
# set up the game to start
|
||||
board := game_start ()
|
||||
player := O
|
||||
display_board (board, player)
|
||||
# loop until the game is over, getting each player to move in turn
|
||||
until game_over (board) do {
|
||||
write (player || " to play next")
|
||||
# based on player, prompt for the next move
|
||||
if (player == O)
|
||||
then (player_O (board, player))
|
||||
else (player_X (board, player))
|
||||
# change player to move
|
||||
player := if (player == O) then X else O
|
||||
display_board (board, player)
|
||||
}
|
||||
# finish by writing out result
|
||||
if game_won_by (board, O)
|
||||
then write ("O won")
|
||||
else if game_won_by (board, X)
|
||||
then write ("X won")
|
||||
else write ("draw") # neither player won, so must be a draw
|
||||
end
|
||||
|
||||
# -- get things started
|
||||
procedure main ()
|
||||
play_game ()
|
||||
end
|
||||
94
Task/Tic-tac-toe/J/tic-tac-toe.j
Normal file
94
Task/Tic-tac-toe/J/tic-tac-toe.j
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
Note 'ttt adjudicates or plays'
|
||||
|
||||
use: markers ttt characters
|
||||
|
||||
characters represent the cell names.
|
||||
|
||||
markers is a length 3 character vector of the
|
||||
characters to use for first and second player
|
||||
followed by the opponent's mark.
|
||||
'XOX' means X plays 1st, O is the other mark,
|
||||
and the first strategy plays 1st.
|
||||
'XOO' means X plays 1st, O is the other mark,
|
||||
and the second strategy moves first.
|
||||
|
||||
The game is set up for the computer as the
|
||||
first strategy (random), and human as second.
|
||||
|
||||
A standard use:
|
||||
'XOX'ttt'abcdefghijkl'
|
||||
|
||||
Example game reformatted w/ emacs artist-mode
|
||||
to fit your display:
|
||||
|
||||
'#-#'ttt'wersdfxcv'
|
||||
w│e│r w│e│r .... -│e│r . -│e│#
|
||||
─┼─┼─ . ─┼─┼─ .. ─┼─┼─ .. ─┼─┼─
|
||||
s│d│f . s│#│f .. s│#│f .. -│#│f
|
||||
─┼─┼─ .. ─┼─┼─ . ─┼─┼─ ... ─┼─┼─
|
||||
x│c│v .. -│c│v . -│c│# .. -│c│#
|
||||
d .. v .. r . VICTORY
|
||||
w│e│r .. w│e│r .. -│e│# .
|
||||
─┼─┼─ ... ─┼─┼─ .. ─┼─┼─ .
|
||||
s│#│f ... s│#│f .. s│#│f .
|
||||
─┼─┼─ .. ─┼─┼─ ... ─┼─┼─ ...
|
||||
x│c│v -│c│# -│c│#
|
||||
-->cell for -? -->cell for -? -->cell for -?
|
||||
x w s
|
||||
)
|
||||
|
||||
while=: conjunction def 'u ^: v ^:_' NB. j assumes while is a verb and needs to know while is a conjunction.
|
||||
|
||||
ttt=: outcome@:((display@:move) while undecided)@:display@:prepare
|
||||
|
||||
blindfolded_variant=: outcome@:display@:(move while undecided)@:display@:prepare
|
||||
|
||||
outcome=: {&(>;:'kitty VICTORY')@:won NB. (outcome does not pass along the state)
|
||||
move=: post locate
|
||||
undecided=: won nor full
|
||||
prepare=: , board@:] NB. form the state vector
|
||||
|
||||
Note 'locate'
|
||||
is a monadic verb. y is the state vector.
|
||||
returns the character of the chosen cell.
|
||||
Generally:
|
||||
locate=: second_strategy`first_strategy@.(first = mark)
|
||||
Simplified:
|
||||
locate=: human_locate NB. human versus human
|
||||
)
|
||||
locate=: human_locate`computer_locate@.(first = mark)
|
||||
|
||||
display=: show [: (1 1,:5 5)&(];.0)@:": [: <"0 fold
|
||||
|
||||
computer_locate=: [: show@{. board -. marks NB. strategy: first available
|
||||
computer_locate=: [: show@({~ ?@:#) board -. marks NB. strategy: random
|
||||
|
||||
human_locate=: monad define
|
||||
state=. y
|
||||
m=. mark state
|
||||
b=. board state
|
||||
cells=. b -. marks state
|
||||
show '-->cell for ' , m , '?'
|
||||
whilst. cell -.@:e. cells do. cell =. {. (1!:1]1) , m end.
|
||||
)
|
||||
|
||||
post=: 2&A.@:(3&{.)@:[ prepare mark@:[`((i.~ board)~)`(board@:[)}
|
||||
|
||||
mark=: {. NB. mark of the current player from state
|
||||
marks=: 2&{. NB. extract both markers from state
|
||||
board=: _9&{. NB. extract board from state
|
||||
first=: 2&{ NB. extract first player from state
|
||||
|
||||
show=: [ smoutput
|
||||
|
||||
full=: 2 = #@:~.
|
||||
won=: test@:fold
|
||||
fold=: 3 3 $ board
|
||||
test=: [: any [: all [: infix_pairs_agree |:@:lines
|
||||
|
||||
lines=: , diagonal , diagonal@:|. , |:
|
||||
diagonal=: (<0 1)&|:
|
||||
all=: *./
|
||||
any=: +./
|
||||
nor=: 8 b.
|
||||
infix_pairs_agree=: 2&(=/\)
|
||||
152
Task/Tic-tac-toe/Java/tic-tac-toe.java
Normal file
152
Task/Tic-tac-toe/Java/tic-tac-toe.java
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
import java.util.Scanner;
|
||||
import java.util.Random;
|
||||
import java.util.InputMismatchException;
|
||||
|
||||
public class TicTacToe
|
||||
{
|
||||
public static char [] gameBoard = {'1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9'};
|
||||
public static Scanner keyboard = new Scanner(System.in);
|
||||
private static int[][] wins = {
|
||||
{0,1,2},
|
||||
{3,4,5},
|
||||
{6,7,8},
|
||||
{0,4,8},
|
||||
{2,4,6},
|
||||
{0,3,6},
|
||||
{1,4,7},
|
||||
{2,5,8}
|
||||
};
|
||||
|
||||
public static void main (String [] args)
|
||||
{
|
||||
System.out.println("*****Tic-Tac-Toe*****");
|
||||
System.out.println("Directions:\n"
|
||||
+ "Tic-Tac-Toe game board has 9 possible marking positions "
|
||||
+ "labeled 1-9.\nTo begin play enter desired position "
|
||||
+ "number to mark with X.\n");
|
||||
|
||||
outputBoard();
|
||||
makeMove();
|
||||
|
||||
int moveCount = 1;
|
||||
|
||||
while(moveCount < gameBoard.length)
|
||||
{
|
||||
computerMove();
|
||||
if(checkBoard()){
|
||||
System.out.println("Computer wins!");
|
||||
break;
|
||||
}
|
||||
makeMove();
|
||||
if(checkBoard()){
|
||||
System.out.println("Player wins!");
|
||||
break;
|
||||
}
|
||||
|
||||
moveCount = moveCount + 2;
|
||||
}
|
||||
}
|
||||
|
||||
public static void outputBoard()
|
||||
{
|
||||
System.out.println("+---+---+---+");
|
||||
System.out.println("| " + gameBoard[0] + " | " + gameBoard[1]
|
||||
+ " | " + gameBoard[2] + " |");
|
||||
System.out.println("+---+---+---+");
|
||||
System.out.println("| " + gameBoard[3] + " | " + gameBoard[4]
|
||||
+ " | " + gameBoard[5] + " |");
|
||||
System.out.println("+---+---+---+");
|
||||
System.out.println("| " + gameBoard[6] + " | " + gameBoard[7]
|
||||
+ " | " + gameBoard[8] + " |");
|
||||
System.out.println("+---+---+---+");
|
||||
}
|
||||
|
||||
public static void makeMove()
|
||||
{
|
||||
|
||||
System.out.println("\nYour Turn, Enter Position #:");
|
||||
int num = getPosition();
|
||||
|
||||
if(gameBoard[num] == 'X' || gameBoard[num] == 'O')
|
||||
{
|
||||
System.out.println("Board Position Already Taken, Try Again.");
|
||||
makeMove();
|
||||
}
|
||||
else
|
||||
{
|
||||
gameBoard[num] = 'X';
|
||||
outputBoard();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static int getPosition()
|
||||
{
|
||||
int num = 0;
|
||||
boolean done = false;
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
num = keyboard.nextInt();
|
||||
|
||||
if(num > gameBoard.length || num <= 0)
|
||||
{
|
||||
System.out.println("Incorrect Position Try Again");
|
||||
}
|
||||
else
|
||||
done = true;
|
||||
}
|
||||
catch(InputMismatchException exception)
|
||||
{
|
||||
System.out.println("Incorrect Entry Format Try Again");
|
||||
keyboard.next();
|
||||
}
|
||||
|
||||
}while(!done);
|
||||
|
||||
return num - 1;
|
||||
}
|
||||
|
||||
|
||||
public static void computerMove()
|
||||
{
|
||||
Random rand = new Random();
|
||||
int num = rand.nextInt(9);
|
||||
|
||||
if(gameBoard[num] == ('X') || gameBoard[num] == ('O'))
|
||||
computerMove();
|
||||
else
|
||||
{
|
||||
System.out.println("\nComputer's Turn.");
|
||||
gameBoard[num] = 'O';
|
||||
outputBoard();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean checkBoard()
|
||||
{
|
||||
for(int[] win:wins)
|
||||
{
|
||||
if(gameBoard[win[0]] != 'O' && gameBoard[win[0]] != 'X')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char winner = gameBoard[win[0]];
|
||||
|
||||
boolean check = true;
|
||||
|
||||
for(int pos:win)
|
||||
{
|
||||
check = check && (gameBoard[pos] == winner);
|
||||
}
|
||||
|
||||
if(check)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
36
Task/Tic-tac-toe/Mathematica/tic-tac-toe.math
Normal file
36
Task/Tic-tac-toe/Mathematica/tic-tac-toe.math
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
DynamicModule[{board = ConstantArray[0, {3, 3}], text = "Playing...",
|
||||
first, rows =
|
||||
Join[#, Transpose@#, {Diagonal@#, Diagonal@Reverse@#}] &},
|
||||
Column@{Graphics[{Thickness[.02],
|
||||
Table[With[{i = i, j = j},
|
||||
Button[{White, Rectangle[{i, j} - 1, {i, j}], Black,
|
||||
Dynamic[Switch[board[[i, j]], 0, Black, 1,
|
||||
Circle[{i, j} - .5, .3], -1,
|
||||
Line[{{{i, j} - .2, {i, j} - .8}, {{i - .2,
|
||||
j - .8}, {i - .8, j - .2}}}]]]},
|
||||
Which[text != "Playing...", board = ConstantArray[0, {3, 3}];
|
||||
text = "Playing...", board[[i, j]] == 0,
|
||||
If[board == ConstantArray[0, {3, 3}],
|
||||
first = {i,
|
||||
j} /. {{2, 2} -> 1, {1 | 3, 1 | 3} -> 2, _ -> 3}];
|
||||
board[[i, j]] = 1;
|
||||
FinishDynamic[];
|
||||
Which[MemberQ[rows[board], {1, 1, 1}], text = "You win.",
|
||||
FreeQ[board, 0], text = "Draw.", True,
|
||||
board[[Sequence @@
|
||||
SortBy[Select[Tuples[{Range@3, Range@3}],
|
||||
board[[Sequence @@ #]] ==
|
||||
0 &], -Total[
|
||||
Sort /@
|
||||
rows[ReplacePart[
|
||||
board, # -> -1]] /. {{-1, -1, -1} ->
|
||||
512, {-1, 1, 1} -> 64, {-1, -1, 0} ->
|
||||
8, {0, 1, 1} -> -1, {_, _, _} -> 0}] -
|
||||
Switch[#, {2, 2}, 1, {1 | 3, 1 | 3},
|
||||
If[first == 2, -1, 0], _,
|
||||
If[first == 2, 0, -1]] &][[1]]]] = -1;
|
||||
Which[MemberQ[rows[board], {-1, -1, -1}],
|
||||
text = "You lost.", FreeQ[board, 0],
|
||||
text = "Draw."]]]]], {i, 1, 3}, {j, 1, 3}], Thickness[.01],
|
||||
Line[{{{1, 0}, {1, 3}}, {{2, 0}, {2, 3}}, {{0, 1}, {3, 1}}, {{0,
|
||||
2}, {3, 2}}}]}], Dynamic@text}]
|
||||
48
Task/Tic-tac-toe/Perl-6/tic-tac-toe.pl6
Normal file
48
Task/Tic-tac-toe/Perl-6/tic-tac-toe.pl6
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
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[$_];
|
||||
}
|
||||
}
|
||||
|
||||
sub free-indexes() {
|
||||
@board.keys.grep: { @board[$_] eq any(1..9) }
|
||||
}
|
||||
|
||||
sub ai-move() {
|
||||
given free-indexes.pick {
|
||||
@board[$_] = 'o';
|
||||
say "I go at: { $_ + 1 }\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub print-board() {
|
||||
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) {
|
||||
@board[$pos - 1] = 'x';
|
||||
} else {
|
||||
say "Sorry, you want to put your 'x' where?";
|
||||
human-move();
|
||||
}
|
||||
}
|
||||
|
||||
for (&ai-move, &human-move) xx * {
|
||||
print-board;
|
||||
.();
|
||||
last if get-winner() or not free-indexes;
|
||||
}
|
||||
|
||||
if get-winner() -> ($player, $across) {
|
||||
say "$player wins across [", ($across >>+>> 1).join(", "), "].";
|
||||
} else {
|
||||
say "How boring, a draw!";
|
||||
}
|
||||
67
Task/Tic-tac-toe/PicoLisp/tic-tac-toe.l
Normal file
67
Task/Tic-tac-toe/PicoLisp/tic-tac-toe.l
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
(load "@lib/simul.l") # for 'game' function
|
||||
|
||||
(de display ()
|
||||
(for Y (3 2 1)
|
||||
(prinl " +---+---+---+")
|
||||
(prin " " Y)
|
||||
(for X (1 2 3)
|
||||
(prin " | " (or (get *Board X Y) " ")) )
|
||||
(prinl " |") )
|
||||
(prinl " +---+---+---+")
|
||||
(prinl " a b c") )
|
||||
|
||||
(de find3 (P)
|
||||
(find
|
||||
'((X Y DX DY)
|
||||
(do 3
|
||||
(NIL (= P (get *Board X Y)))
|
||||
(inc 'X DX)
|
||||
(inc 'Y DY)
|
||||
T ) )
|
||||
(1 1 1 1 2 3 1 1)
|
||||
(1 2 3 1 1 1 1 3)
|
||||
(1 1 1 0 0 0 1 1)
|
||||
(0 0 0 1 1 1 1 -1) ) )
|
||||
|
||||
(de myMove ()
|
||||
(when
|
||||
(game NIL 8
|
||||
'((Flg) # Moves
|
||||
(unless (find3 (or (not Flg) 0))
|
||||
(make
|
||||
(for (X . L) *Board
|
||||
(for (Y . P) L
|
||||
(unless P
|
||||
(link
|
||||
(cons
|
||||
(cons X Y (or Flg 0))
|
||||
(list X Y) ) ) ) ) ) ) ) )
|
||||
'((Mov) # Move
|
||||
(set (nth *Board (car Mov) (cadr Mov)) (cddr Mov)) )
|
||||
'((Flg) # Cost
|
||||
(if (find3 (or Flg 0)) -100 0) ) )
|
||||
(let Mov (caadr @)
|
||||
(set (nth *Board (car Mov) (cadr Mov)) 0) )
|
||||
(display) ) )
|
||||
|
||||
(de yourMove (X Y)
|
||||
(and
|
||||
(sym? X)
|
||||
(>= 3 (setq X (- (char X) 96)) 1)
|
||||
(num? Y)
|
||||
(>= 3 Y 1)
|
||||
(not (get *Board X Y))
|
||||
(set (nth *Board X Y) T)
|
||||
(display) ) )
|
||||
|
||||
(de main ()
|
||||
(setq *Board (make (do 3 (link (need 3)))))
|
||||
(display) )
|
||||
|
||||
(de go Args
|
||||
(cond
|
||||
((not (yourMove (car Args) (cadr Args)))
|
||||
"Illegal move!" )
|
||||
((find3 T) "Congratulation, you won!")
|
||||
((not (myMove)) "No moves")
|
||||
((find3 0) "Sorry, you lost!") ) )
|
||||
208
Task/Tic-tac-toe/Prolog/tic-tac-toe-1.pro
Normal file
208
Task/Tic-tac-toe/Prolog/tic-tac-toe-1.pro
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
:- use_module('min-max.pl').
|
||||
|
||||
:-dynamic box/2.
|
||||
:- dynamic tic_tac_toe_window/1.
|
||||
|
||||
% Computer begins.
|
||||
tic-tac-toe(computer) :-
|
||||
V is random(9),
|
||||
TTT = [_,_,_,_,_,_ ,_,_,_],
|
||||
nth0(V, TTT, o),
|
||||
display_tic_tac_toe(TTT).
|
||||
|
||||
% Player begins
|
||||
tic-tac-toe(me) :-
|
||||
TTT = [_,_,_,_,_,_ ,_,_,_],
|
||||
display_tic_tac_toe(TTT).
|
||||
|
||||
|
||||
display_tic_tac_toe(TTT) :-
|
||||
retractall(box(_,_)),
|
||||
retractall(tic_tac_toe_window(_)),
|
||||
new(D, window('Tic-tac-Toe')),
|
||||
send(D, size, size(170,170)),
|
||||
X = 10, Y = 10,
|
||||
display(D, X, Y, 0, TTT),
|
||||
assert(tic_tac_toe_window(D)),
|
||||
send(D, open).
|
||||
|
||||
display(_, _, _, _, []).
|
||||
|
||||
display(D, X, Y, N, [A,B,C|R]) :-
|
||||
display_line(D, X, Y, N, [A,B,C]),
|
||||
Y1 is Y+50,
|
||||
N3 is N+3,
|
||||
display(D, X, Y1, N3, R).
|
||||
|
||||
|
||||
display_line(_, _, _, _, []).
|
||||
display_line(D, X, Y, N, [C|R]) :-
|
||||
( nonvar(C)-> C1 = C; C1 = ' '),
|
||||
new(B, tic_tac_toe_box(C1)),
|
||||
assertz(box(N, B)),
|
||||
send(D, display, B, point(X, Y)),
|
||||
X1 is X + 50,
|
||||
N1 is N+1,
|
||||
display_line(D, X1, Y, N1, R).
|
||||
|
||||
|
||||
|
||||
% class tic_tac_toe_box
|
||||
% display an 'x' when the player clicks
|
||||
% display an 'o' when the computer plays
|
||||
:- pce_begin_class(tic_tac_toe_box, box, "Graphical window with text").
|
||||
|
||||
variable(mess, any, both, "text to display").
|
||||
|
||||
initialise(P, Lbl) :->
|
||||
send(P, send_super, initialise),
|
||||
send(P, slot, mess, Lbl),
|
||||
WS = 50, HS = 50,
|
||||
send(P, size, size(WS,HS)),
|
||||
send(P, recogniser,
|
||||
handler_group(new(click_gesture(left,
|
||||
'',
|
||||
single,
|
||||
message(@receiver, my_click))))).
|
||||
|
||||
% the box is clicked
|
||||
my_click(B) :->
|
||||
send(B, set_val, x),
|
||||
send(@prolog, play).
|
||||
|
||||
% only works when the box is "free"
|
||||
set_val(B, Val) :->
|
||||
get(B, slot, mess, ' '),
|
||||
send(B, slot, mess, Val),
|
||||
send(B, redraw),
|
||||
send(B, flush).
|
||||
|
||||
|
||||
% redefined method to display custom graphical objects.
|
||||
'_redraw_area'(P, A:area) :->
|
||||
send(P, send_super, '_redraw_area', A),
|
||||
%we display the text
|
||||
get(P, slot, mess, Lbl),
|
||||
new(Str1, string(Lbl)),
|
||||
get_object(P, area, area(X,Y,W,H)),
|
||||
send(P, draw_box, X, Y, W, H),
|
||||
send(P, draw_text, Str1,
|
||||
font(times, normal, 30),
|
||||
X, Y, W, H, center, center).
|
||||
|
||||
:- pce_end_class.
|
||||
|
||||
play :-
|
||||
numlist(0, 8, L),
|
||||
maplist(init, L, TTT),
|
||||
finished(x, TTT, Val),
|
||||
( Val = 2 -> send(@display, inform,'You win !'),
|
||||
tic_tac_toe_window(D),
|
||||
send(D, destroy)
|
||||
; ( Val = 1 -> send(@display, inform,'Draw !'),
|
||||
tic_tac_toe_window(D),
|
||||
send(D, destroy)
|
||||
; next_move(TTT, TT1),
|
||||
maplist(display, L, TT1),
|
||||
finished(o, TT1, V),
|
||||
( V = 2 -> send(@display, inform,'I win !'),
|
||||
tic_tac_toe_window(D),
|
||||
send(D, destroy)
|
||||
; ( V = 1 -> send(@display, inform,'Draw !'),
|
||||
tic_tac_toe_window(D),
|
||||
send(D, destroy)
|
||||
; true)))).
|
||||
|
||||
|
||||
% use minmax to compute the next move
|
||||
next_move(TTT, TT1) :-
|
||||
minimax(o, 0, 1024, TTT, _V1- TT1).
|
||||
|
||||
|
||||
% we display the new board
|
||||
display(I, V) :-
|
||||
nonvar(V),
|
||||
box(I, V1),
|
||||
send(V1, set_val, V).
|
||||
|
||||
display(_I, _V).
|
||||
|
||||
% we create the board for minmax
|
||||
init(I, V) :-
|
||||
box(I, V1),
|
||||
get(V1, slot, mess, V),
|
||||
V \= ' '.
|
||||
|
||||
init(_I, _V).
|
||||
|
||||
% winning position for the player P ?
|
||||
winned(P, [A1, A2, A3, A4, A5, A6, A7, A8, A9]) :-
|
||||
(is_winning_line(P, [A1, A2, A3]);
|
||||
is_winning_line(P, [A4, A5, A6]);
|
||||
is_winning_line(P, [A7, A8, A9]);
|
||||
is_winning_line(P, [A1, A4, A7]);
|
||||
is_winning_line(P, [A2 ,A5, A8]);
|
||||
is_winning_line(P, [A3, A6, A9]);
|
||||
is_winning_line(P, [A1, A5, A9]);
|
||||
is_winning_line(P, [A3, A5, A7])).
|
||||
|
||||
|
||||
is_winning_line(P, [A, B, C]) :-
|
||||
nonvar(A), A = P,
|
||||
nonvar(B), B = P,
|
||||
nonvar(C), C = P.
|
||||
|
||||
% Winning position for the player
|
||||
eval(Player, Deep, TTT, V) :-
|
||||
winned(Player, TTT),
|
||||
( Player = o -> V is 1000 - 50 * Deep; V is -1000+ 50 * Deep).
|
||||
|
||||
% Loosing position for the player
|
||||
eval(Player, Deep, TTT, V) :-
|
||||
select(Player, [o,x], [Player1]),
|
||||
winned(Player1, TTT),
|
||||
( Player = x -> V is 1000 - 50 * Deep; V is -1000+ 50 * Deep).
|
||||
|
||||
% Draw position
|
||||
eval(_Player, _Deep, TTT, 0) :-
|
||||
include(var, TTT, []).
|
||||
|
||||
|
||||
% we fetch the free positions of the board
|
||||
possible_move(TTT, LMove) :-
|
||||
new(C, chain),
|
||||
forall(between(0,8, I),
|
||||
( nth0(I, TTT, X),
|
||||
( var(X) -> send(C, append, I); true))),
|
||||
chain_list(C, LMove).
|
||||
|
||||
% we create the new position when the player P clicks
|
||||
% the box "N"
|
||||
assign_move(P, TTT, N, TT1) :-
|
||||
copy_term(TTT, TT1),
|
||||
nth0(N, TT1, P).
|
||||
|
||||
% We fetch all the possible boards obtained from board TTT
|
||||
% for the player P
|
||||
get_next(Player, Deep, TTT, Player1, Deep1, L):-
|
||||
possible_move(TTT, LMove),
|
||||
select(Player, [o,x], [Player1]),
|
||||
Deep1 is Deep + 1,
|
||||
maplist(assign_move(Player, TTT), LMove, L).
|
||||
|
||||
|
||||
% The game is over ?
|
||||
% Player P wins
|
||||
finished(P, TTT, 2) :-
|
||||
winned(P, TTT).
|
||||
|
||||
% Draw
|
||||
finished(_P, TTT, 1) :-
|
||||
include(var, TTT, []).
|
||||
|
||||
% the game is not over
|
||||
finished(_P, _TTT, 0) .
|
||||
|
||||
% minmax must knows when the computer plays
|
||||
% (o for ordinateur in French)
|
||||
computer(o).
|
||||
26
Task/Tic-tac-toe/Prolog/tic-tac-toe-2.pro
Normal file
26
Task/Tic-tac-toe/Prolog/tic-tac-toe-2.pro
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
:- module('min-max.pl', [minimax/5]).
|
||||
|
||||
% minimax(Player, Deep, MaxDeep, B, V-B)
|
||||
% @arg1 : current player at this level
|
||||
% @arg2 : current level of recursion
|
||||
% @arg3 : max level of recursion (in this version of the game no use : set to 1024 !)
|
||||
% @arg4 : current board
|
||||
% @arg5 : B is the evaluation of the board, the result is V-B to know the new board
|
||||
|
||||
% Here we get an evaluation
|
||||
minimax(Player, Deep, MaxDeep, B, V-B) :-
|
||||
( eval(Player, Deep, B, V) -> true
|
||||
; % in this version of the game this second division always fails
|
||||
( Deep > MaxDeep -> V is random(1000) - 1000)).
|
||||
|
||||
% here we must compute all the possible moves to know the evaluation of the board
|
||||
minimax(Player, Deep, MaxDeep, B, V) :-
|
||||
get_next(Player, Deep, B, Player1, Deep1, L),
|
||||
maplist(minimax(Player1, Deep1, MaxDeep), L, LV),
|
||||
maplist(lie, L, LV, TLV),
|
||||
sort(TLV, SLVTmp),
|
||||
( computer(Player) -> reverse(SLVTmp, SLV); SLV = SLVTmp),
|
||||
SLV = [V | _R].
|
||||
|
||||
|
||||
lie(TTT, V-_, V-TTT).
|
||||
74
Task/Tic-tac-toe/Python/tic-tac-toe-1.py
Normal file
74
Task/Tic-tac-toe/Python/tic-tac-toe-1.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
'''
|
||||
Tic-tac-toe game player.
|
||||
Input the index of where you wish to place your mark at your turn.
|
||||
'''
|
||||
|
||||
import random
|
||||
|
||||
board = list('123456789')
|
||||
wins = ((0,1,2), (3,4,5), (6,7,8),
|
||||
(0,3,6), (1,4,7), (2,5,8),
|
||||
(0,4,8), (2,4,6))
|
||||
|
||||
def printboard():
|
||||
print('\n'.join(' '.join(board[x:x+3]) for x in(0,3,6)))
|
||||
|
||||
def score():
|
||||
for w in wins:
|
||||
b = board[w[0]]
|
||||
if b in 'XO' and all (board[i] == b for i in w):
|
||||
return b, [i+1 for i in w]
|
||||
return None, None
|
||||
|
||||
def finished():
|
||||
return all (b in 'XO' for b in board)
|
||||
|
||||
def space():
|
||||
return [ b for b in board if b not in 'XO']
|
||||
|
||||
def my_turn(xo):
|
||||
options = space()
|
||||
choice = random.choice(options)
|
||||
board[int(choice)-1] = xo
|
||||
return choice
|
||||
|
||||
def your_turn(xo):
|
||||
options = space()
|
||||
while True:
|
||||
choice = input(" Put your %s in any of these positions: %s "
|
||||
% (xo, ''.join(options))).strip()
|
||||
if choice in options:
|
||||
break
|
||||
print( "Whoops I don't understand the input" )
|
||||
board[int(choice)-1] = xo
|
||||
return choice
|
||||
|
||||
def me(xo='X'):
|
||||
printboard()
|
||||
print('I go at', my_turn(xo))
|
||||
return score()
|
||||
assert not s[0], "\n%s wins across %s" % s
|
||||
|
||||
def you(xo='O'):
|
||||
printboard()
|
||||
# Call my_turn(xo) below for it to play itself
|
||||
print('You went at', your_turn(xo))
|
||||
return score()
|
||||
assert not s[0], "\n%s wins across %s" % s
|
||||
|
||||
|
||||
print(__doc__)
|
||||
while not finished():
|
||||
s = me('X')
|
||||
if s[0]:
|
||||
printboard()
|
||||
print("\n%s wins across %s" % s)
|
||||
break
|
||||
if not finished():
|
||||
s = you('O')
|
||||
if s[0]:
|
||||
printboard()
|
||||
print("\n%s wins across %s" % s)
|
||||
break
|
||||
else:
|
||||
print('\nA draw')
|
||||
91
Task/Tic-tac-toe/Python/tic-tac-toe-2.py
Normal file
91
Task/Tic-tac-toe/Python/tic-tac-toe-2.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
'''
|
||||
Tic-tac-toe game player.
|
||||
Input the index of where you wish to place your mark at your turn.
|
||||
'''
|
||||
|
||||
import random
|
||||
|
||||
board = list('123456789')
|
||||
wins = ((0,1,2), (3,4,5), (6,7,8),
|
||||
(0,3,6), (1,4,7), (2,5,8),
|
||||
(0,4,8), (2,4,6))
|
||||
|
||||
def printboard():
|
||||
print('\n-+-+-\n'.join('|'.join(board[x:x+3]) for x in(0,3,6)))
|
||||
|
||||
def score(board=board):
|
||||
for w in wins:
|
||||
b = board[w[0]]
|
||||
if b in 'XO' and all (board[i] == b for i in w):
|
||||
return b, [i+1 for i in w]
|
||||
return None
|
||||
|
||||
def finished():
|
||||
return all (b in 'XO' for b in board)
|
||||
|
||||
def space(board=board):
|
||||
return [ b for b in board if b not in 'XO']
|
||||
|
||||
def my_turn(xo, board):
|
||||
options = space()
|
||||
choice = random.choice(options)
|
||||
board[int(choice)-1] = xo
|
||||
return choice
|
||||
|
||||
def my_better_turn(xo, board):
|
||||
'Will return a next winning move or block your winning move if possible'
|
||||
ox = 'O' if xo =='X' else 'X'
|
||||
oneblock = None
|
||||
options = [int(s)-1 for s in space(board)]
|
||||
for choice in options:
|
||||
brd = board[:]
|
||||
brd[choice] = xo
|
||||
if score(brd):
|
||||
break
|
||||
if oneblock is None:
|
||||
brd[choice] = ox
|
||||
if score(brd):
|
||||
oneblock = choice
|
||||
else:
|
||||
choice = oneblock if oneblock is not None else random.choice(options)
|
||||
board[choice] = xo
|
||||
return choice+1
|
||||
|
||||
def your_turn(xo, board):
|
||||
options = space()
|
||||
while True:
|
||||
choice = input("\nPut your %s in any of these positions: %s "
|
||||
% (xo, ''.join(options))).strip()
|
||||
if choice in options:
|
||||
break
|
||||
print( "Whoops I don't understand the input" )
|
||||
board[int(choice)-1] = xo
|
||||
return choice
|
||||
|
||||
def me(xo='X'):
|
||||
printboard()
|
||||
print('\nI go at', my_better_turn(xo, board))
|
||||
return score()
|
||||
|
||||
def you(xo='O'):
|
||||
printboard()
|
||||
# Call my_turn(xo, board) below for it to play itself
|
||||
print('\nYou went at', your_turn(xo, board))
|
||||
return score()
|
||||
|
||||
|
||||
print(__doc__)
|
||||
while not finished():
|
||||
s = me('X')
|
||||
if s:
|
||||
printboard()
|
||||
print("\n%s wins along %s" % s)
|
||||
break
|
||||
if not finished():
|
||||
s = you('O')
|
||||
if s:
|
||||
printboard()
|
||||
print("\n%s wins along %s" % s)
|
||||
break
|
||||
else:
|
||||
print('\nA draw')
|
||||
105
Task/Tic-tac-toe/REXX/tic-tac-toe.rexx
Normal file
105
Task/Tic-tac-toe/REXX/tic-tac-toe.rexx
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*REXX program plays (with a human) the tic-tac-toe game on an NxN grid.*/
|
||||
oops =$ '***error!*** '; cell# ='cell number' /*a couple of literals*/
|
||||
$=copies('─',9) /*eyecatcher literal for messages*/
|
||||
sing='│─┼'; jam='║'; bar='═'; junc='╬'; dbl=jam || bar || junc
|
||||
sw=80-1 /*LINESIZE() bif would be better.*/
|
||||
parse arg N hm cm .,@.; if N=='' then N=3; oN=N /*specifying some args?*/
|
||||
N=abs(N); NN=N*N; middle=NN%2+N%2 /*if N < 0, computer goes first.*/
|
||||
if N<2 then do; say oops 'tic-tac-toe grid is too small: ' N; exit; end
|
||||
pad=copies(left('',sw%NN),1+(N<5)) /*display padding: 6x6 in 80 cols*/
|
||||
if hm=='' then hm='X'; if cm=='' then cm='O' /*markers: Human, Computer*/
|
||||
hm=aChar(hm,'human'); cm=aChar(cm,'computer') /*process the markers.*/
|
||||
if hm==cm then cm='X' /*Human wants the "O"? Sheesh! */
|
||||
if oN<0 then call Hmove middle /*comp moves 1st? Choose middling*/
|
||||
else call showGrid /*···also checks for wins & draws*/
|
||||
do forever /*'til the cows come home, by gum*/
|
||||
call CBLF /*do carbon-based lifeform's move*/
|
||||
call Hal /*figure Hal the computer's move.*/
|
||||
end /*forever····showGrid does wins & draws*/
|
||||
/*──────────────────────────────────ACHAR subroutine────────────────────*/
|
||||
aChar: parse arg x; L=length(x) /*process markers.*/
|
||||
if L==1 then return x /*1 char, as is. */
|
||||
if L==2 & datatype(x,'X') then return x2c(x) /*2 chars, hex. */
|
||||
if L==3 & datatype(x,'W') then return d2c(x) /*3 chars, decimal*/
|
||||
say oops 'illegal character or character code for' arg(2) "marker: " x
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────CBLF subroutine─────────────────────*/
|
||||
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#: +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 /*do forever*/
|
||||
end /*select*/
|
||||
end /*forever*/
|
||||
@.ox=hm /*place a marker for the human.*/
|
||||
call showGrid /*and show the tic-tac-toe grid.*/
|
||||
return
|
||||
/*──────────────────────────────────Hal subroutine──────────────────────*/
|
||||
Hal: select /*Hal will try various moves. */
|
||||
when win(cm,N-1) then call Hmove ,ec /* winning move? */
|
||||
when win(hm,N-1) then call Hmove ,ec /* blocking move? */
|
||||
when @.middle=='' then call Hmove middle /* center move. */
|
||||
when @.N.N=='' then call Hmove ,N N /*bR corner move. */
|
||||
when @.N.1=='' then call Hmove ,N 1 /*bL corner move. */
|
||||
when @.1.N=='' then call Hmove ,1 N /*tR corner move. */
|
||||
when @.1.1=='' then call Hmove ,1 1 /*tL corner move. */
|
||||
otherwise call Hmove ,ac /*some blank cell.*/
|
||||
end /*select*/
|
||||
return
|
||||
/*──────────────────────────────────HMOVE subroutine────────────────────*/
|
||||
Hmove: parse arg Hplace,dr dc; if Hplace=='' then Hplace = (dr-1)*N + dc
|
||||
@.Hplace=cm /*put marker for Hal the computer*/
|
||||
say; say $ 'computer places a marker ['cm"] at cell number " Hplace
|
||||
call showGrid
|
||||
return
|
||||
/*──────────────────────────────────SHOWGRID subroutine─────────────────*/
|
||||
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
|
||||
say; z=0 /* [↑] create grid coörds.*/
|
||||
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#*/
|
||||
_= _||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)
|
||||
end /*j*/
|
||||
say
|
||||
if win(hm) then call tell 'You ('hm") won!"
|
||||
if win(cm) then call tell 'The computer ('cm") won."
|
||||
if \open then call tell 'This tic-tac-toe is a draw.'
|
||||
return
|
||||
/*──────────────────────────────────TELL subroutine─────────────────────*/
|
||||
tell: do 4; say; end; say center(' 'arg(1)" ",sw,'─'); do 5; say; end
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────WIN subroutine──────────────────────*/
|
||||
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 @c=ec; if _==N | (_>=w & ec\=='') then return 1
|
||||
end /*r*/ /*if 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 @c=ec; if _==N | (_>=w & ec\=='') then return 1
|
||||
end /*r*/ /*EC is a r,c version of cell #*/
|
||||
_=0; ec= /*see if 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 /*see if winning ascending diag.*/
|
||||
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
|
||||
143
Task/Tic-tac-toe/Ruby/tic-tac-toe.rb
Normal file
143
Task/Tic-tac-toe/Ruby/tic-tac-toe.rb
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
module TicTacToe
|
||||
|
||||
class Game
|
||||
def initialize(player1Class, player2Class)
|
||||
@board = Array.new(10)
|
||||
@free_positions = (1..9).to_a
|
||||
@players = [player1Class.new(self), player2Class.new(self)]
|
||||
@turn = rand(2)
|
||||
puts "#{@players[@turn]} goes first."
|
||||
@players[@turn].marker = "X"
|
||||
@players[nextTurn].marker = "O"
|
||||
@winning_rows = [[1,2,3],[4,5,6],[7,8,9],[1,4,7],[2,5,8],[3,6,9],[1,5,9],[3,5,7]]
|
||||
end
|
||||
attr_reader :free_positions, :winning_rows, :board
|
||||
|
||||
def play
|
||||
loop do
|
||||
player = @players[@turn]
|
||||
idx = player.select
|
||||
puts "#{player} selects #{player.marker} position #{idx}"
|
||||
@board[idx] = player.marker
|
||||
@free_positions.delete(idx)
|
||||
|
||||
# check for a winner
|
||||
@winning_rows.each do |row|
|
||||
if row.all? {|idx| @board[idx] == player.marker}
|
||||
puts "#{player} wins!"
|
||||
print
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
# no winner, is board full?
|
||||
if @free_positions.empty?
|
||||
puts "It's a draw."
|
||||
print
|
||||
return
|
||||
end
|
||||
|
||||
nextTurn!
|
||||
end
|
||||
end
|
||||
|
||||
def nextTurn
|
||||
(@turn + 1) % 2
|
||||
end
|
||||
|
||||
def nextTurn!
|
||||
@turn = nextTurn
|
||||
end
|
||||
|
||||
def opponent
|
||||
@players[nextTurn]
|
||||
end
|
||||
|
||||
def print
|
||||
puts [1,2,3].map {|i| @board[i].nil? ? i : @board[i]}.join("|")
|
||||
puts "-+-+-"
|
||||
puts [4,5,6].map {|i| @board[i].nil? ? i : @board[i]}.join("|")
|
||||
puts "-+-+-"
|
||||
puts [7,8,9].map {|i| @board[i].nil? ? i : @board[i]}.join("|")
|
||||
end
|
||||
end
|
||||
|
||||
class Player
|
||||
def initialize(game)
|
||||
@game = game
|
||||
@marker = nil
|
||||
end
|
||||
attr_accessor :marker
|
||||
end
|
||||
|
||||
class HumanPlayer < Player
|
||||
def initialize(game)
|
||||
super(game)
|
||||
end
|
||||
|
||||
def select
|
||||
@game.print
|
||||
loop do
|
||||
print "Select your #{marker} position: "
|
||||
selection = $stdin.gets.to_i
|
||||
if not @game.free_positions.include?(selection)
|
||||
puts "Position #{selection} is not available. Try again."
|
||||
next
|
||||
end
|
||||
return selection
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Human"
|
||||
end
|
||||
end
|
||||
|
||||
class ComputerPlayer < Player
|
||||
def initialize(game)
|
||||
super(game)
|
||||
end
|
||||
|
||||
def group_row(row, opponent)
|
||||
markers = {self.marker => [], opponent.marker => [], nil => []} .
|
||||
merge(row.group_by {|idx| @game.board[idx]})
|
||||
#p [row, markers].inspect
|
||||
markers
|
||||
end
|
||||
|
||||
def select
|
||||
index = nil
|
||||
opponent = @game.opponent
|
||||
|
||||
# look for winning rows
|
||||
@game.winning_rows.each do |row|
|
||||
markers = group_row(row, opponent)
|
||||
if markers[self.marker].length == 2 and markers[nil].length == 1
|
||||
return markers[nil].first
|
||||
end
|
||||
end
|
||||
|
||||
# look for opponent's winning rows to block
|
||||
@game.winning_rows.each do |row|
|
||||
markers = group_row(row, opponent)
|
||||
if markers[opponent.marker].length == 2 and markers[nil].length == 1
|
||||
return markers[nil].first
|
||||
end
|
||||
end
|
||||
|
||||
# need some logic here to get the computer to pick a smarter position
|
||||
|
||||
# simply pick a position in order of preference
|
||||
[5].concat([1,3,7,9].shuffle).concat([2,4,6,8].shuffle).each do |pos|
|
||||
return pos if @game.free_positions.include?(pos)
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Computer"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
TicTacToe::Game.new(TicTacToe::ComputerPlayer, TicTacToe::ComputerPlayer).play
|
||||
TicTacToe::Game.new(TicTacToe::HumanPlayer, TicTacToe::ComputerPlayer).play
|
||||
102
Task/Tic-tac-toe/Run-BASIC/tic-tac-toe.run
Normal file
102
Task/Tic-tac-toe/Run-BASIC/tic-tac-toe.run
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
' ---------------------------
|
||||
' TIC TAC TOE
|
||||
' ---------------------------
|
||||
winBox$ = "123 456 789 159 147 258 369 357"
|
||||
boxPos$ = "123 231 456 564 789 897 159 591 357 753 132 465 798 174 285 396 159 471 582 693 147 258 369 195 375"
|
||||
ai$ = "519628374"
|
||||
ox$ = "OX"
|
||||
[newGame]
|
||||
for i = 1 to 9
|
||||
box$(i) = ""
|
||||
next i
|
||||
goto [shoTic]
|
||||
|
||||
[loop]
|
||||
for j = 1 to 2
|
||||
tic$ = mid$(ox$,j,1)
|
||||
for i = 1 to 25
|
||||
b$ = word$(boxPos$,i," ")
|
||||
b1 = val(mid$(b$,1,1))
|
||||
b2 = val(mid$(b$,2,1))
|
||||
b3 = val(mid$(b$,3,1))
|
||||
if box$(b1) = tic$ AND box$(b2) = tic$ AND box$(b3) = "" then
|
||||
box$(b3) = "O"
|
||||
goto [shoTic]
|
||||
end if
|
||||
next i
|
||||
next j
|
||||
if box$(1) = "O" AND box$(5) = "X" and box$(9) = "X" then
|
||||
if box$(3) = "" then
|
||||
box$(3) = "O"
|
||||
goto [shoTic]
|
||||
end if
|
||||
if box$(7) = "" then
|
||||
box$(7) = "O"
|
||||
goto [shoTic]
|
||||
end if
|
||||
end if
|
||||
for i = 1 to 9
|
||||
b1 = val(mid$(ai$,i,1))
|
||||
if box$(b1) = "" then
|
||||
box$(b1) = "O"
|
||||
exit for
|
||||
end if
|
||||
next i
|
||||
|
||||
[shoTic]
|
||||
cls
|
||||
' ----------------------------------------
|
||||
' show tic tac toe screen
|
||||
' ----------------------------------------
|
||||
html "<table border=1 width=300px height=225px><TR>"
|
||||
for i = 1 to 9
|
||||
html "<td align=center width=33%><h1>"
|
||||
if box$(i) <> "" then
|
||||
html box$(i)
|
||||
else
|
||||
button #box, " ";box$(i);" ", [doTic]
|
||||
#box setkey(str$(i))
|
||||
end if
|
||||
if i mod 3 = 0 then html "</tr><tr>"
|
||||
next i
|
||||
html "</table>"
|
||||
gosub [checkWin]
|
||||
wait
|
||||
|
||||
[doTic]
|
||||
box$(val(EventKey$)) = "X"
|
||||
turn = 1
|
||||
gosub [checkWin]
|
||||
goto [loop]
|
||||
|
||||
' --- check for a winner ----------
|
||||
[checkWin]
|
||||
for i = 1 to 8
|
||||
b$ = word$(winBox$,i," ")
|
||||
b1 = val(mid$(b$,1,1))
|
||||
b2 = val(mid$(b$,2,1))
|
||||
b3 = val(mid$(b$,3,1))
|
||||
if box$(b1) = "O" and box$(b2) = "O" and box$(b3) = "O" then
|
||||
print "You Loose!"
|
||||
goto [playAgain]
|
||||
end if
|
||||
if box$(b1) = "X" and box$(b2) = "X" and box$(b3) = "X" then
|
||||
print "You Win!"
|
||||
goto [playAgain]
|
||||
end if
|
||||
next i
|
||||
|
||||
moveCount = 0
|
||||
for i = 1 to 9
|
||||
if box$(i) <> "" then moveCount = moveCount + 1
|
||||
next i
|
||||
if moveCount = 9 then
|
||||
print "Draw!"
|
||||
goto [playAgain]
|
||||
end if
|
||||
RETURN
|
||||
|
||||
[playAgain]
|
||||
input "Play again (y/n)";p$
|
||||
if upper$(p$) = "Y" then goto [newGame]
|
||||
end
|
||||
82
Task/Tic-tac-toe/Scala/tic-tac-toe.scala
Normal file
82
Task/Tic-tac-toe/Scala/tic-tac-toe.scala
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package object tictactoe {
|
||||
val Human = 'X'
|
||||
val Computer = 'O'
|
||||
val BaseBoard = ('1' to '9').toList
|
||||
val WinnerLines = List((0,1,2), (3,4,5), (6,7,8), (0,3,6), (1,4,7), (2,5,8), (0,4,8), (2,4,6))
|
||||
val randomGen = new util.Random(System.currentTimeMillis)
|
||||
}
|
||||
|
||||
package tictactoe {
|
||||
|
||||
class Board(aBoard : List[Char] = BaseBoard) {
|
||||
|
||||
def availableMoves = aBoard.filter(c => c != Human && c != Computer)
|
||||
|
||||
def availableMovesIdxs = for ((c,i) <- aBoard.zipWithIndex if c != Human && c != Computer) yield i
|
||||
|
||||
def computerPlays = new Board(aBoard.updated(availableMovesIdxs(randomGen.nextInt(availableMovesIdxs.length)), Computer))
|
||||
|
||||
def humanPlays(move : Char) = new Board(aBoard.updated(aBoard.indexOf(move), Human))
|
||||
|
||||
def isDraw = aBoard.forall(c => c == Human || c == Computer)
|
||||
|
||||
def isWinner(winner : Char) =
|
||||
WinnerLines.exists{case (i,j,k) => aBoard(i) == winner && aBoard(j) == winner && aBoard(k) == winner}
|
||||
|
||||
def isOver = isWinner(Computer) || isWinner(Human) || isDraw
|
||||
|
||||
def print {
|
||||
aBoard.grouped(3).foreach(row => println(row(0) + " " + row(1) + " " + row(2)))
|
||||
}
|
||||
|
||||
def printOverMessage {
|
||||
if (isWinner(Human)) println("You win.")
|
||||
else if (isWinner(Computer)) println("Computer wins.")
|
||||
else if (isDraw) println("It's a draw.")
|
||||
else println("Not over yet, or something went wrong.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
object TicTacToe extends Application {
|
||||
|
||||
def play(board : Board, turn : Char) {
|
||||
|
||||
// Reads a char from input until it is one of
|
||||
// the available moves in the current board
|
||||
def readValidMove() : Char = {
|
||||
print("Choose a move: ")
|
||||
val validMoves = board.availableMoves
|
||||
val move = readChar
|
||||
if (validMoves.contains(move)) {
|
||||
move
|
||||
} else {
|
||||
println("Invalid move. Choose another one in " + validMoves)
|
||||
readValidMove()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
board.print
|
||||
|
||||
if (board.isOver) {
|
||||
board.printOverMessage
|
||||
return
|
||||
}
|
||||
|
||||
if (turn == Human) { // Human plays
|
||||
val nextBoard = board.humanPlays(readValidMove)
|
||||
play(nextBoard, Computer)
|
||||
} else { // Computer plays
|
||||
println("Computer plays: ")
|
||||
val nextBoard = board.computerPlays
|
||||
play(nextBoard, Human)
|
||||
}
|
||||
}
|
||||
|
||||
play(new Board(),Human)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
121
Task/Tic-tac-toe/Tcl/tic-tac-toe.tcl
Normal file
121
Task/Tic-tac-toe/Tcl/tic-tac-toe.tcl
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
package require Tcl 8.6
|
||||
|
||||
# This code splits the players from the core game engine
|
||||
oo::class create TicTacToe {
|
||||
variable board player letter who
|
||||
constructor {player1class player2class} {
|
||||
set board {1 2 3 4 5 6 7 8 9}
|
||||
set player(0) [$player1class new [self] [set letter(0) "X"]]
|
||||
set player(1) [$player2class new [self] [set letter(1) "O"]]
|
||||
set who 0
|
||||
}
|
||||
|
||||
method PrintBoard {} {
|
||||
lassign $board a1 b1 c1 a2 b2 c2 a3 b3 c3
|
||||
puts [format " %s | %s | %s" $a1 $b1 $c1]
|
||||
puts "---+---+---"
|
||||
puts [format " %s | %s | %s" $a2 $b2 $c2]
|
||||
puts "---+---+---"
|
||||
puts [format " %s | %s | %s" $a3 $b3 $c3]
|
||||
}
|
||||
|
||||
method WinForSomeone {} {
|
||||
foreach w {
|
||||
{0 1 2} {3 4 5} {6 7 8} {0 3 6} {1 4 7} {2 5 8} {0 4 8} {2 4 6}
|
||||
} {
|
||||
set b [lindex $board [lindex $w 0]]
|
||||
if {$b ni "X O"} continue
|
||||
foreach i $w {if {[lindex $board $i] ne $b} break}
|
||||
if {[lindex $board $i] eq $b} {
|
||||
foreach p $w {lappend w1 [expr {$p+1}]}
|
||||
return [list $b $w1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
method status {} {
|
||||
return $board
|
||||
}
|
||||
|
||||
method IsDraw {} {
|
||||
foreach b $board {if {[string is digit $b]} {return false}}
|
||||
return true
|
||||
}
|
||||
|
||||
method legalMoves {} {
|
||||
foreach b $board {if {[string is digit $b]} {lappend legal $b}}
|
||||
return $legal
|
||||
}
|
||||
|
||||
method DoATurn {} {
|
||||
set legal [my legalMoves]
|
||||
my PrintBoard
|
||||
while 1 {
|
||||
set move [$player($who) turn]
|
||||
if {$move in $legal} break
|
||||
puts "Illegal move!"
|
||||
}
|
||||
lset board [expr {$move - 1}] $letter($who)
|
||||
$player($who) describeMove $move
|
||||
set who [expr {1 - $who}]
|
||||
return [my WinForSomeone]
|
||||
}
|
||||
|
||||
method game {} {
|
||||
puts " Tic-tac-toe game player.
|
||||
Input the index of where you wish to place your mark at your turn.\n"
|
||||
while {![my IsDraw]} {
|
||||
set winner [my DoATurn]
|
||||
if {$winner eq ""} continue
|
||||
lassign $winner winLetter winSites
|
||||
my PrintBoard
|
||||
puts "\n$winLetter wins across \[[join $winSites {, }]\]"
|
||||
return $winLetter
|
||||
}
|
||||
puts "\nA draw"
|
||||
}
|
||||
}
|
||||
|
||||
# Stupid robotic player
|
||||
oo::class create RandomRoboPlayer {
|
||||
variable g
|
||||
constructor {game letter} {
|
||||
set g $game
|
||||
}
|
||||
method turn {} {
|
||||
set legal [$g legalMoves]
|
||||
return [lindex $legal [expr {int(rand()*[llength $legal])}]]
|
||||
}
|
||||
method describeMove {move} {
|
||||
puts "I go at $move"
|
||||
}
|
||||
}
|
||||
|
||||
# Interactive human player delegate
|
||||
oo::class create HumanPlayer {
|
||||
variable g char
|
||||
constructor {game letter} {
|
||||
set g $game
|
||||
set char $letter
|
||||
}
|
||||
method turn {} {
|
||||
set legal [$g legalMoves]
|
||||
puts ">>> Put your $char in any of these positions: [join $legal {}]"
|
||||
while 1 {
|
||||
puts -nonewline ">>> "
|
||||
flush stdout
|
||||
gets stdin number
|
||||
if {$number in $legal} break
|
||||
puts ">>> Whoops I don't understand the input!"
|
||||
}
|
||||
return $number
|
||||
}
|
||||
method describeMove {move} {
|
||||
puts "You went at $move"
|
||||
}
|
||||
}
|
||||
|
||||
# Assemble the pieces
|
||||
set ttt [TicTacToe new HumanPlayer RandomRoboPlayer]
|
||||
$ttt game
|
||||
145
Task/Tic-tac-toe/XPL0/tic-tac-toe.xpl0
Normal file
145
Task/Tic-tac-toe/XPL0/tic-tac-toe.xpl0
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
\The computer marks its moves with an "O" and the player uses an "X". The
|
||||
\ numeric keypad is used to make the player's move.
|
||||
\
|
||||
\ 7 | 8 | 9
|
||||
\ ---+---+---
|
||||
\ 4 | 5 | 6
|
||||
\ ---+---+---
|
||||
\ 1 | 2 | 3
|
||||
\
|
||||
\The player always goes first, but the 0 key is used to skip a move. Thus
|
||||
\ it can be used to let the computer play first. Esc terminates program.
|
||||
|
||||
inc c:\cxpl\codes; \intrinsic routine declarations
|
||||
def X0=16, Y0=10; \coordinates of character in upper-left square
|
||||
int I0,
|
||||
PMove, \player's move (^0..^9)
|
||||
Key; \keystroke
|
||||
int X, O; \bit arrays for player and computer
|
||||
\ bit 0 corresponds to playing square 1, etc.
|
||||
|
||||
|
||||
proc HLine(X, Y); \Draw a horizontal line
|
||||
int X, Y;
|
||||
int I;
|
||||
[Cursor(X, Y);
|
||||
for I:= 0 to 10 do ChOut(0, ^Ä);
|
||||
]; \HLine
|
||||
|
||||
|
||||
proc VLine(X, Y); \Draw a vertical line over the above horizontal line
|
||||
int X, Y;
|
||||
int I;
|
||||
[for I:= 0 to 4 do
|
||||
[Cursor(X, Y+I);
|
||||
ChOut(0, if I&1 then ^Å else ^³);
|
||||
];
|
||||
]; \VLine
|
||||
|
||||
|
||||
func Won(p); \Return 'true' if player P has won
|
||||
int P;
|
||||
int T, I;
|
||||
[T:= [$007, $038, $1C0, $049, $092, $124, $111, $054];
|
||||
for I:= 0 to 7 do \check if player matches a bit pattern for 3 in a row
|
||||
if (P & T(I)) = T(I) then return true;
|
||||
return false;
|
||||
]; \Won
|
||||
|
||||
|
||||
func Cats; \Return 'true' if no more moves available (Cat's game)
|
||||
[if (X ! O) = $1FF then \all bit positions played
|
||||
[Cursor(17, 20);
|
||||
Text(0, "A draw!");
|
||||
return true;
|
||||
];
|
||||
return false;
|
||||
]; \Cats
|
||||
|
||||
|
||||
proc DoMove(P, M, Ch); \Make move in player's bit array and display it
|
||||
int P, \address of player's bit array
|
||||
M, \index 0..8 where bit is placed
|
||||
Ch;
|
||||
int I, X, Y;
|
||||
[P(0):= P(0) ! 1<<M; \make move
|
||||
|
||||
I:= M / 3; \display move
|
||||
X:= Rem(0) * 4;
|
||||
Y:= (2-I) * 2;
|
||||
Cursor(X+X0, Y+Y0);
|
||||
ChOut(0, Ch);
|
||||
]; \DoMove
|
||||
|
||||
|
||||
func Try(P); \Return the value of the best node for player P
|
||||
int P; \address of player's bit array
|
||||
int P1, I, I0, V, V0;
|
||||
[P1:= if P = addr X then addr O else addr X;
|
||||
|
||||
if Won(P1(0)) then return -1;
|
||||
if (X ! O) = $1FF then return 0;
|
||||
|
||||
V0:= -1; \assume the worst
|
||||
for I:= 0 to 8 do \for all of the squares...
|
||||
if ((O!X) & 1<<I) = 0 then \if square is unused
|
||||
[P(0):= P(0) ! 1<<I; \make tenative move
|
||||
V:= -(extend(Try(P1))); \get value
|
||||
if V > V0 then \save best value
|
||||
[V0:= V; I0:= I];
|
||||
P(0):= P(0) & ~(1<<I); \undo tenative move
|
||||
];
|
||||
return V0 & $FF ! I0<<8;
|
||||
]; \Try
|
||||
|
||||
|
||||
proc PlayGame; \Play one game
|
||||
[ChOut(0, $0C\FF\); \clear screen with a form feed
|
||||
HLine(X0-1, Y0+1); \draw grid (#)
|
||||
HLine(X0-1, Y0+3);
|
||||
VLine(X0+2, Y0);
|
||||
VLine(X0+6, Y0);
|
||||
|
||||
X:= 0; O:= 0; \initialize player's bit arrays to empty
|
||||
loop [loop [PMove:= ChIn(1); \GET PLAYER'S MOVE (X)
|
||||
if PMove = $1B\Esc\ then
|
||||
[SetVid(3); exit]; \restore display and end program
|
||||
if PMove = ^0 then quit;
|
||||
if PMove>=^1 & PMove<=^9 & \check for legal move
|
||||
((X!O) & 1<<(PMove-^1)) = 0 then quit;
|
||||
ChOut(0, 7\Bel\); \beep the dude
|
||||
];
|
||||
if PMove # ^0 then
|
||||
[DoMove(addr X, PMove-^1, ^X);
|
||||
if Won(X) then
|
||||
[Cursor(17, 20);
|
||||
Text(0, "X wins!");
|
||||
quit;
|
||||
];
|
||||
];
|
||||
if Cats then quit;
|
||||
|
||||
I0:= Try(addr O) >>8; \GET COMPUTER'S MOVE (O)
|
||||
DoMove(addr O, I0, ^O); \do best move
|
||||
if Won(O) then
|
||||
[Cursor(17, 20);
|
||||
Text(0, "O wins!");
|
||||
quit;
|
||||
];
|
||||
if Cats then quit;
|
||||
];
|
||||
]; \PlayGame
|
||||
|
||||
|
||||
int CpuReg;
|
||||
[SetVid(1); \set 40x25 text mode
|
||||
CpuReg:= GetReg; \turn off annoying flashing cursor
|
||||
CpuReg(0):= $0100; \ with BIOS interrupt 10h, function 01h
|
||||
CpuReg(2):= $2000; \set cursor type to disappear
|
||||
SoftInt($10);
|
||||
loop [PlayGame;
|
||||
Key:= ChIn(1); \keep playing games until Esc key is hit
|
||||
if Key = $1B\Esc\ then
|
||||
[SetVid(3); exit]; \clear screen & restore normal text mode
|
||||
];
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue