isefire

t3_v2

Apr 24th, 2016
741
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Erlang 15.64 KB | None | 0 0
  1. %%%-------------------------------------------------------------------
  2. %%% @author Daniel latham
  3. %%% @copyright (C) 2016, Daniel Latham
  4. %%% @doc
  5. %%% Implement a two client version of a text based tic-tac-toe program. To this end develop a module t3
  6. %%% that contains the following functions:
  7. %%%
  8. %%% – newgame() starts a new game node and waits for an opponent.
  9. %%%
  10. %%% – playwith(Opponent) connects to another Erlang node identified by Opponent and starts a new game.
  11. %%%   If the Opponent does not exist, a call to playwith results in an error. When the game starts the two clients
  12. %%%   randomly decide who starts the game.
  13. %%%
  14. %%% – placetoken(Coordinate) validates that Coordinate is a valid move and places a new token at field Coordinate.
  15. %%%   The move is also communicated to the opponent’s client. Coordinate is coordinate in the form of a1, . . ., c3.
  16. %%%   When a winning position is reached or no more move is possible, the program announces the result on both clients
  17. %%%   and the game terminates. If it is not a client’s turn, a call to placetoken prints an error message.
  18. %%%   If there is no ongoing game, a call to placetoken may result in an error.
  19. %%%
  20. %%% – tell(Message) sends a message to the opponent. The message will be printed on the console.
  21. %%%
  22. %%% Hint: This site may give you some ideas: http://ninenines.eu/articles/tictactoe/
  23. %%% Note: If the problem description is unclear, please use the Canvas forum to seek clarification.
  24. %%% (20 points – extra credit) Extend the two client version so the game can be played in a distributed environment.
  25. %%%
  26. %%%TORUN:
  27. %%% Open two terminals and connect to moat.cis.uab.edu
  28. %%% You should see two vulcan machines
  29. %%% Go to the directory where this file is saved
  30. %%% Type below where YOURNAME and OTHERNAME are consistent
  31. %%%   1$ erl -sname YOURNAME -setcookie .erlang.cookie
  32. %%%   2$ erl -sname OTHERNAME -setcookie .erlang.cookie
  33. %%% In both type the following
  34. %%%   (YOURNAME@vulcanX)> c(t3).
  35. %%%   (OTHERNAME@vulcanY)> c(t3).
  36. %%% Next, start the game with player one(can be you or other, using you)
  37. %%%   (YOURNAME@vulcanX)> t3:newgame().
  38. %%% Connect to game from player two
  39. %%%   (OTHERNAME@vulcanY)> t3:playwith(YOURNAME@vulcanX).
  40. %%%
  41. %%% @end
  42. %%% Created : 16. Apr 2016 2:20 PM
  43. %%%-------------------------------------------------------------------
  44. -module(t3_v2).
  45. -author("Daniel Latham").
  46.  
  47. %% API
  48.  
  49. -export([newgame/0, playwith/1, tell/1, client/0, data/1, placetoken/1]).
  50.  
  51. %%% Starts new game for player
  52. %%% Use this before trying to connect
  53. newgame() ->
  54.   io:fwrite("Newgame created for Player~n"),
  55.   My_Game_PID = spawn(t3_v2, client, []),
  56.   % Register name of client so that other client can communicate with this process
  57.   % on this node
  58.   register(player, My_Game_PID),
  59.   My_Game_PID.
  60.  
  61. %%% Use this to play with another node on the same or other machine on the same network
  62. %%% Usage: t3:playwith(bob@address).
  63. playwith(Other_Game_Node)->
  64.   Response = net_adm:ping(Other_Game_Node),
  65.   % Check that response is not a 'pang'
  66.   if
  67.     Response == pang ->
  68.       io:fwrite("Invalid host or username. It is possible that the host or user is "),
  69.       io:fwrite("offline or your secret cookie is incorrectly setup. Please try again.~n");
  70.     true ->
  71.       My_Game_PID = newgame(),
  72.       {player, Other_Game_Node} ! {connect, My_Game_PID}
  73.   end.
  74.  
  75. %%% Sends message to other player's node
  76. tell(Message) ->
  77.   Other = get_player(),
  78.   Other ! {message, Message}.
  79.  
  80.  
  81. %%% Generates client for saving data(board, other player, etc)
  82. data(OtherPlayer, Board, Piece, Lock)->
  83.   receive
  84.     {get_player, Node} ->
  85.       Node ! {give_player, OtherPlayer},
  86.       data(OtherPlayer, Board, Piece, Lock);
  87.  
  88.     {get_board, Node} ->
  89.       Node ! {give_board, Board},
  90.       data(OtherPlayer, Board, Piece, Lock);
  91.  
  92.     {get_piece, Node} ->
  93.       Node ! {give_piece, Piece},
  94.       data(OtherPlayer, Board, Piece, Lock);
  95.  
  96.     {get_lock, Node} ->
  97.       Node ! {give_lock, Lock},
  98.       data(OtherPlayer, Board, Piece, Lock);
  99.  
  100.     {set_board, NewBoard} ->
  101.       data(OtherPlayer, NewBoard, Piece, Lock);
  102.  
  103.     {set_lock, NewLock} ->
  104.       data(OtherPlayer, Board, Piece, NewLock)
  105.   end.
  106. % Initial state with only other player's node
  107. data(OtherPlayer) ->
  108.   receive
  109.     {get_player, Node} ->
  110.       Node ! {give_player, OtherPlayer},
  111.       data(OtherPlayer);
  112.     {set_up_board, NewBoard, NewPiece, Lock} ->
  113.       data(OtherPlayer, NewBoard, NewPiece, Lock)
  114.   end.
  115.  
  116.  
  117. %%% Two clients generated that talk to each other, one on both systems
  118. client() ->
  119.   receive
  120.     % Add Other_Player to our data process, send back our node+client
  121.     {connect, Other_Player} ->
  122.       io:fwrite("Connected to Other Player, ~p~n", [Other_Player]),
  123.       % Spawn new data process
  124.       DataPID = spawn(t3_v2, data, [Other_Player]),
  125.       % Set up global name for data process
  126.       register(data, DataPID),
  127.       Other_Player ! {connected, self()};
  128.     % Connected to Other_Player, add full node+client process to our
  129.     % data process
  130.     {connected, Other_Player} ->
  131.       io:fwrite("Connected to Other Player, ~p~n", [Other_Player]),
  132.       % Spawn new data process
  133.       DataPID = spawn(t3_v2, data, [Other_Player]),
  134.       % Set up global name for data process
  135.       register(data, DataPID),
  136.       % Decide who gets to go first
  137.       % Change seed to something random enough
  138.       random:seed(now()),
  139.       My_Num = random:uniform(),
  140.       Other_Num = random:uniform(),
  141.       if
  142.         My_Num >= Other_Num ->
  143.           io:fwrite("'~p' >= '~p'; You begin game...~n", [My_Num, Other_Num]),
  144.           Other_Player ! {print_whobegins, My_Num, Other_Num},
  145.           generate_game();
  146.         My_Num < Other_Num ->
  147.           io:fwrite("'~p' < '~p'; Other Player begins game...~n", [My_Num, Other_Num]),
  148.           Other_Player ! {print_whobegins, My_Num, Other_Num},
  149.           Other_Player ! {gen_game};
  150.         true ->
  151.           ok
  152.       end;
  153.  
  154.     % Prints who begins the game for the node that created the new game first
  155.     % Player 2 being the one that connected to Player 1
  156.     {print_whobegins, Other_Num, My_Num} ->
  157.       if
  158.         Other_Num >= My_Num ->
  159.           io:fwrite("'~p' >= '~p'; Other Player begins game...~n", [Other_Num, My_Num]);
  160.         true ->
  161.           io:fwrite("'~p' < '~p'; You begin game...~n", [Other_Num, My_Num])
  162.       end;
  163.  
  164.     {set_up_board} ->
  165.       % Creates board
  166.       Board = new_board(),
  167.       % Sets piece
  168.       Piece = o,
  169.       % Sets LOCK
  170.       Lock = closed,
  171.       % Grabs data process
  172.       Data = whereis(data),
  173.       % Set our board piece to 'o' and lock set to closed
  174.       Data ! {set_up_board, Board, Piece, Lock},
  175.       io:fwrite("You are 'o'.~n"),
  176.       io:fwrite("Other player is making move..Please wait~n");
  177.      
  178.      
  179.     {message, Message} ->
  180.       io:fwrite("Other Player ~p says: ~p~n", [get_player(), Message]);
  181.  
  182.     {gen_game} ->
  183.       io:fwrite("Generating game...~n~n"),
  184.       generate_game();
  185.  
  186.     {results, Board, Result} ->
  187.       % 0 for tie, 1 for other wins
  188.       io:fwrite("~n~n$$$$$$$$$$$$FINAL BOARD$$$$$$$$$$$~n~n"),
  189.       print_board(Board),
  190.       if
  191.         Result == 0 ->
  192.           io:fwrite("~nIt's a tie! Thanks for playing!~n");
  193.         true ->
  194.           io:fwrite("~nSorry! You lose, Player '~p'!~n", [get_piece()])
  195.       end;
  196.  
  197.     {your_turn, Coordinate, NewBoard} ->
  198.       set_board(NewBoard),
  199.       io:fwrite("~n~nOther Player set coordinate '~p'~n~n", [Coordinate]),
  200.       print_board(NewBoard),
  201.       %%% unset lock
  202.       set_lock(open),
  203.       Piece = get_piece(),
  204.       io:fwrite("~nYou are '~p'. Use 'placetoken(a1...c3)' to place token on board.~n", [Piece])
  205.   end,
  206.   client().
  207.  
  208. %%% Generates the board, piece, and lock and sends to data process
  209. generate_game() ->
  210.   % Creates board
  211.   Board = new_board(),
  212.   % Sets piece
  213.   Piece = x,
  214.   % Sets LOCK
  215.   Lock = open,
  216.   % Grabs data process
  217.   Data = whereis(data),
  218.   % Set our board piece to 'x' and lock set to open
  219.   Data ! {set_up_board, Board, Piece, Lock},
  220.   % Send message to other node that they must wait, and that they are 'o'
  221.   Other = get_player(),
  222.   Other ! {set_up_board},
  223.   % Print message with board
  224.   print_board(Board),
  225.   io:fwrite("~nYou are 'x'. Use 'placetoken(a1...c3)' to place token on board.~n").
  226.  
  227.  
  228.  
  229. %%% Below are numerous getters and setters
  230. %%% Self explanatory
  231. get_player() ->
  232.   Data = whereis(data),
  233.   Data ! {get_player, self()},
  234.   receive
  235.     {give_player, OtherPlayer} ->
  236.       OtherPlayer
  237.   end.
  238.  
  239. get_board() ->
  240.   Data = whereis(data),
  241.   Data ! {get_board, self()},
  242.   receive
  243.     {give_board, Board} ->
  244.       Board
  245.   end.
  246.  
  247. get_piece() ->
  248.   Data = whereis(data),
  249.   Data ! {get_piece, self()},
  250.   receive
  251.     {give_piece, Piece} ->
  252.       Piece
  253.   end.
  254.  
  255. get_lock() ->
  256.   Data = whereis(data),
  257.   Data ! {get_lock, self()},
  258.   receive
  259.     {give_lock, Lock} ->
  260.       Lock
  261.   end.
  262.  
  263. set_board(Board) ->
  264.   Data = whereis(data),
  265.   Data ! {set_board, Board}.
  266.  
  267.  
  268. set_lock(Lock) ->
  269.   Data = whereis(data),
  270.   Data ! {set_lock, Lock}.
  271.  
  272.  
  273. %%% Possibly the most complicated function, placetoken places a token (a1... c3)
  274. %%% Onto the board. Locks, already placed pieces, and winning states are assessed here
  275. placetoken(Coordinate) ->
  276.   Board = get_board(),
  277.   Piece = get_piece(),
  278.   Lock = get_lock(),
  279.   Possible = {a1, a2, a3, b1, b2, b3, c1, c2, c3},
  280.   Is_Poss = lists:member(Coordinate, tuple_to_list(Possible)),
  281.   if
  282.     Lock == closed ->
  283.       io:fwrite("It is not your turn yet. Please wait.~n");
  284.     Is_Poss ->
  285.       io:fwrite("~p chosen.~n", [Coordinate]),
  286.       Free = check_element(Coordinate, Board),
  287.       if
  288.         Free == false ->
  289.           io:fwrite("Please choose a free space~n");
  290.         true ->
  291.           % Switched Y and X for compatability
  292.           {Y, X} = convert_coordinate(Coordinate),
  293.           New_Board = place_element(Piece, X, Y, Board),
  294.           set_board(New_Board),
  295.           % Check board to see if you won
  296.           Won = check(get_board()),
  297.           Other = get_player(),
  298.           if
  299.             {victory, x} == Won ->
  300.               io:fwrite("~n~n$$$$$$$$$$$$FINAL BOARD$$$$$$$$$$$~n~n"),
  301.               print_board(get_board()),
  302.               io:fwrite("~nCongratulations! You won, Player '~p'~n", [get_piece()]),
  303.               Other ! {results, get_board(), 1};
  304.             {victory, o} == Won ->
  305.               io:fwrite("~n~n$$$$$$$$$$$$FINAL BOARD$$$$$$$$$$$~n~n"),
  306.               print_board(get_board()),
  307.               io:fwrite("~nCongratulations! You won, Player '~p'~n", [get_piece()]),
  308.               Other ! {results, get_board(), 1};
  309.            draw == Won ->
  310.               io:fwrite("~n~n$$$$$$$$$$$$FINAL BOARD$$$$$$$$$$$~n~n"),
  311.               print_board(get_board()),
  312.               io:fwrite("~nIt's a tie! Thanks for playing!~n"),
  313.               Other ! {results, get_board(), 1};
  314.           true ->
  315.               print_board(get_board()),
  316.               Other ! {your_turn, Coordinate, get_board()},
  317.               % SET LOCK
  318.               set_lock(closed)
  319.           end,
  320.           ok
  321.       end;
  322.     true ->
  323.       io:fwrite("No correct unit chosen. Correct units include: ~p.~n", [Possible])
  324.   end.
  325.  
  326. %%% Converts coordinate atom into {X, Y} numerical tuple
  327. convert_coordinate(Co) ->
  328.   Co_str = atom_to_list(Co),
  329.   Co_str_0 = string:substr(Co_str, 1, 1),
  330.   Co_str_1 = string:substr(Co_str, 2, 1),
  331.   if
  332.     Co_str_0 == "a" ->
  333.       X = 1;
  334.     Co_str_0 == "b" ->
  335.       X = 2;
  336.     Co_str_0 == "c" ->
  337.       X = 3;
  338.     true ->
  339.       X = -1
  340.   end,
  341.   if
  342.     Co_str_1 == "1" ->
  343.       Y = 1;
  344.     Co_str_1 == "2" ->
  345.       Y = 2;
  346.     Co_str_1 == "3" ->
  347.       Y = 3;
  348.     true ->
  349.       Y = -1
  350.   end,
  351.   {X, Y}.
  352.  
  353.  
  354.  
  355. %%% prints the board by calling greater function below
  356. print_board(Board) ->
  357.   print_board(Board, 1).
  358.  
  359.  
  360. %%% Prints the board, recursively going line by line, piece by piece
  361. print_board(Board, Index) ->
  362.   if
  363.     Index < 10 ->
  364.       L = element(Index, Board);
  365.     true ->
  366.       L = undefined
  367.   end,
  368.   New_Index = Index + 1,
  369.   case Index of
  370.     1 ->
  371.       io:fwrite("#############~n"),
  372.       io:fwrite("#  ~p ", [L]),
  373.       print_board(Board, New_Index);
  374.     2 ->
  375.       io:fwrite(" ~p ", [L]),
  376.       print_board(Board, New_Index);
  377.     3 ->
  378.       io:fwrite(" ~p  #~n", [L]),
  379.       print_board(Board, New_Index);
  380.     4 ->
  381.       io:fwrite("#  ~p ", [L]),
  382.       print_board(Board, New_Index);
  383.     5 ->
  384.       io:fwrite(" ~p ", [L]),
  385.       print_board(Board, New_Index);
  386.     6 ->
  387.       io:fwrite(" ~p  #~n", [L]),
  388.       print_board(Board, New_Index);
  389.     7 ->
  390.       io:fwrite("#  ~p ", [L]),
  391.       print_board(Board, New_Index);
  392.     8 ->
  393.       io:fwrite(" ~p ", [L]),
  394.       print_board(Board, New_Index);
  395.     9 ->
  396.       io:fwrite(" ~p  #~n", [L]),
  397.       io:fwrite("#############~n"),
  398.       print_board(Board, New_Index);
  399.     _ ->
  400.       ok
  401.   end.
  402.  
  403.  
  404. %%% Generates a new board and returns it
  405. new_board() ->
  406.   {l, l, l,
  407.     l, l, l,
  408.     l, l, l}.
  409.  
  410. %%% Places an element on the board based on the X, Y coordinate
  411. place_element(Who, X, Y, Board) ->
  412.   setelement((Y - 1) * 3 + X, Board, Who).
  413.  
  414. %%% Checks the element in question to make sure it is not overwritten
  415. %%% This is also done with pattern matching
  416. check_element(Element, Board) ->
  417.   if
  418.     Element == a1 ->
  419.       {Key, _, _,
  420.         _, _, _,
  421.         _, _, _} = Board;
  422.     Element == a2 ->
  423.       {_, Key, _,
  424.         _, _, _,
  425.         _, _, _} = Board;
  426.     Element == a3 ->
  427.       {_, _, Key,
  428.         _, _, _,
  429.         _, _, _} = Board;
  430.     Element == b1 ->
  431.       {_, _, _,
  432.         Key, _, _,
  433.         _, _, _} = Board;
  434.     Element == b2 ->
  435.       {_, _, _,
  436.         _, Key, _,
  437.         _, _, _} = Board;
  438.     Element == b3 ->
  439.       {_, _, _,
  440.         _, _, Key,
  441.         _, _, _} = Board;
  442.     Element == c1 ->
  443.       {_, _, _,
  444.         _, _, _,
  445.         Key, _, _} = Board;
  446.     Element == c2 ->
  447.       {_, _, _,
  448.         _, _, _,
  449.         _, Key, _} = Board;
  450.     Element == c3 ->
  451.       {_, _, _,
  452.         _, _, _,
  453.         _, _, Key} = Board;
  454.     true ->
  455.       io:fwrite("Should never get here~n"),
  456.       Key = undefined
  457.   end,
  458.   if
  459.     Key == x ->
  460.       io:fwrite("Place ~p taken by 'x'~n", [Element]),
  461.       false;
  462.     Key == o ->
  463.       io:fwrite("Place ~p taken by 'o'~n", [Element]),
  464.       false;
  465.     true ->
  466.       io:fwrite("Place ~p is free.~n", [Element]),
  467.       true
  468.   end.
  469.  
  470. %%% Checks to see if payer has won the game or a tie
  471. %%% Basically just matches the board with a prewritten board
  472. check(Board) ->
  473.   case Board of
  474.     {x, x, x,
  475.       _, _, _,
  476.       _, _, _} -> {victory, x};
  477.  
  478.     {_, _, _,
  479.       x, x, x,
  480.       _, _, _} -> {victory, x};
  481.  
  482.     {_, _, _,
  483.       _, _, _,
  484.       x, x, x} -> {victory, x};
  485.  
  486.     {x, _, _,
  487.       x, _, _,
  488.       x, _, _} -> {victory, x};
  489.  
  490.     {_, x, _,
  491.       _, x, _,
  492.       _, x, _} -> {victory, x};
  493.  
  494.     {_, _, x,
  495.       _, _, x,
  496.       _, _, x} -> {victory, x};
  497.  
  498.     {x, _, _,
  499.       _, x, _,
  500.       _, _, x} -> {victory, x};
  501.  
  502.     {_, _, x,
  503.       _, x, _,
  504.       x, _, _} -> {victory, x};
  505.  
  506.     {o, o, o,
  507.       _, _, _,
  508.       _, _, _} -> {victory, o};
  509.  
  510.     {_, _, _,
  511.       o, o, o,
  512.       _, _, _} -> {victory, o};
  513.  
  514.     {_, _, _,
  515.       _, _, _,
  516.       o, o, o} -> {victory, o};
  517.  
  518.     {o, _, _,
  519.       o, _, _,
  520.       o, _, _} -> {victory, o};
  521.  
  522.     {_, o, _,
  523.       _, o, _,
  524.       _, o, _} -> {victory, o};
  525.  
  526.     {_, _, o,
  527.       _, _, o,
  528.       _, _, o} -> {victory, o};
  529.  
  530.     {o, _, _,
  531.       _, o, _,
  532.       _, _, o} -> {victory, o};
  533.  
  534.     {_, _, o,
  535.       _, o, _,
  536.       o, _, _} -> {victory, o};
  537.  
  538.     {A, B, C,
  539.       D, E, F,
  540.       G, H, I} when A =/= l, B =/= l, C =/= l,
  541.       D =/= l, E =/= l, F =/= l,
  542.       G =/= l, H =/= l, I =/= l ->
  543.       draw;
  544.  
  545.     _ -> ok
  546.   end.
Advertisement