Created
July 9, 2016 22:46
-
-
Save yurapyon/53a5a576d2211c186c9a682572f6a751 to your computer and use it in GitHub Desktop.
tic tac toe with computer player
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local string = require"string" | |
local fmt = string.format | |
-- ==&== BOARD ==&== | |
local function new_board() | |
return {{" "," "," "}, | |
{" "," "," "}, | |
{" "," "," "}} | |
end | |
local function print_board(board) | |
local function print_row(row) | |
for col = 1,2 do | |
io.write(fmt(" %s |",board[row][col])) | |
end | |
io.write(fmt(" %s \n", board[row][3])) | |
end | |
for row = 1, 2 do | |
print_row(row) | |
io.write("___|___|___\n") | |
end | |
print_row(3) | |
io.write(" | | \n") | |
end | |
-- ==&== CHECK ==&== | |
--NOTE: for check functions: | |
--returns nil for no matches or match of " " | |
-- players letter for match of player letters | |
local function check_col(board, col) | |
for row = 1, 2 do | |
if board[row][col] ~= board[row+1][col] then | |
return nil | |
end | |
end | |
if board [1][col] ~= " " then | |
return board[1][col] | |
end | |
return nil | |
end | |
local function check_row(board, row) | |
for col = 1, 2 do | |
if board[row][col] ~= board[row][col+1] then | |
return nil | |
end | |
end | |
if board [row][1] ~= " " then | |
return board[row][1] | |
end | |
return nil | |
end | |
-- NOTE: | |
-- up diagonal is _ _ X | |
-- _ X _ | |
-- X _ _ | |
-- not up is the other diagonal | |
local function check_diag(board, check_up) | |
if check_up then | |
if board[1][3] == board[2][2] | |
and board[2][2] == board[3][1] then | |
if board[2][2] ~= " " then | |
return board[2][2] | |
end | |
end | |
else | |
if board[1][1] == board[2][2] | |
and board[2][2] == board[3][3] then | |
if board[2][2] ~= " " then | |
return board[2][2] | |
end | |
end | |
end | |
return nil | |
end | |
local function check_board(board) | |
local ret | |
for i=1,3 do | |
ret = ret or check_col(board, i) | |
ret = ret or check_row(board, i) | |
end | |
ret = ret or check_diag(board, true) | |
ret = ret or check_diag(board, false) | |
return ret | |
end | |
-- ==&== READ ==&== | |
local function computer_put_coord(board, letter) | |
while true do | |
local col, row = math.random(3), math.random(3) | |
if board[col][row] == " " then | |
board[col][row] = letter | |
return col, row | |
end | |
end | |
end | |
local function read_for_and_put_coord(board, letter) | |
while true do | |
local input = io.read() | |
if input ~= "" then | |
--just pressing enter does not give error but io.read loop continues | |
--the way lua string.find works is it finds the first instance of the format string | |
-- and can return the "captured" digits (denoted by parens) | |
-- with the format i am using below, | |
-- an input of " 1 2" will return "1" and "2" | |
-- an input of " 1 2 3" will return "1" and "2" even though "2 3" fits the format | |
-- an input of "1.5 2 " will return "5" and "2" | |
-- as this is the first found pattern that fits the format | |
-- lua does not read "1.5" as a digit but rather a string. | |
-- a decimal would need to be found with the format: "(%d)%.(%d)" | |
-- which an input of "1.5" will return "1" and "5" (haha) | |
-- side note: "%." in the format escapes a '.' as '.' is reserved | |
--side note #2: string.find will return the location of the found string | |
-- as the first two return values | |
-- then all following return values are captured strings | |
-- here, these first two return values are "dummied" to the variable _ | |
-- because we don't need them | |
local _, _, col, row = string.find(input, "%s-(%d)%s+(%d)") | |
col = tonumber(col) | |
row = tonumber(row) | |
if col and row then | |
if col < 4 and col > 0 and row < 4 and row >0 then | |
if board[col][row] == " " then | |
board[col][row] = letter | |
break | |
else | |
io.write("HEY someones already put a letter there!!!\n") | |
end | |
else | |
io.write(fmt("sadly, you cant put your letter at (%d, %d)\n", x, y)) | |
end | |
else | |
io.write("you cant put your letter... there...(o.O\n") | |
end | |
io.write("please try again...\n") | |
end | |
end | |
end | |
local function read_for_letter() | |
while true do | |
local _,_,ret = string.find(io.read(), "%s-(.)") | |
if ret then | |
return ret | |
end | |
end | |
end | |
-- returns true for yes | |
-- or false for no | |
local function read_for_y_or_n(default_to) | |
if default_to == nil then default_to = false end | |
while true do | |
local _, _, ret = string.find(io.read(), "%s-(.)") | |
if not ret then | |
return default_to | |
elseif ret == "y" or ret == "Y" or ret == "yes" then | |
return true | |
elseif ret == "n" or ret == "N" or ret == "no" then | |
return false | |
else | |
io.write(fmt("'%s' is not, exactly, a vaild answer...\ntry again pls!\n", ret)) | |
end | |
end | |
end | |
-- ==&== MAIN ==&== | |
local computer_player = false | |
local function main() | |
io.write" welcome to tic tac toe! \n" | |
io.write" ~~~~~~~~~~~~~~~~~~~~~~~ \n" | |
local p1,p2 | |
local choose_letters = true | |
local first_coord = true | |
io.write"would you like to play against a computer player? [Y,n]\n" | |
computer_player = read_for_y_or_n(true) | |
if computer_player then | |
--generate fresh seed for the game | |
math.randomseed(os.time()) | |
end | |
while true do --loop for repeat games | |
if choose_letters then | |
io.write"player 1 choose your letter!\n" | |
p1 = read_for_letter() | |
if p1 == "x" then | |
p2 = "o" | |
elseif p1 == "X" then | |
p2 = "O" | |
elseif p1 == "o" then | |
p2 = "x" | |
elseif p1 == "O" then | |
p2 = "X" | |
else | |
while true do | |
if computer_player then | |
--generate number between unicode char values A and Z | |
-- then use string.format to turn into a char | |
p2 = fmt("%c", math.random(65,90)) | |
if p1 ~= p2 then break end | |
else | |
io.write("player 2 choose your letter!\n") | |
p2 = read_for_letter() | |
if p2 ~= p1 then | |
break | |
else | |
io.write("ya can't pick the same letter as player 1......\n") | |
end | |
end | |
end | |
end | |
end | |
io.write(fmt("\nplayer 1 is %s's\n%s is %s's\n" | |
, p1 | |
, computer_player and "computer" or "player 2" | |
, p2)) | |
io.write("lets play!\n\n") | |
local board = new_board() | |
local outcome = nil | |
local p1s_turn = true | |
local turns = 0 | |
while not outcome do | |
-- turn | |
if first_coord then | |
io.write("*whisper* please format your coords as: over#[space]down#\n") | |
first_coord = false | |
end | |
if computer_player and not p1s_turn then | |
--you will only get here for a computer player | |
local col, row = computer_put_coord(board, p2) | |
io.write(fmt("computer player has placed thier letter at %d %d\n", col, row)) | |
--note: i would like to put a sleep function here | |
-- however this is not built into lua and would have to be brought in via FFI | |
-- its pretty trivial to do this but i don't really want to risk the | |
-- code not working on your computer (as the sleep function is OS specific) | |
-- and while its also trivial to check for OS, i feel better being 100% safe haha | |
else | |
io.write(fmt("%s pick a coordinate...\n", p1s_turn and "player 1" or "player 2")) | |
read_for_and_put_coord(board, p1s_turn and p1 or p2) | |
end | |
p1s_turn = not p1s_turn | |
turns = turns + 1 | |
-- print and chek | |
print_board(board) | |
outcome = check_board(board) | |
if turns >= 9 then | |
break | |
end | |
end | |
io.write("\nfinissshhh...\n\n") | |
if not outcome then | |
io.write("dangg it was a draww..\n") | |
else | |
if outcome == p1 then | |
io.write("o gr8 job player 1! real nice going..\n") | |
else | |
if computer_player then | |
io.write("the computer has defeated you (somehow)\n") | |
else | |
io.write("o gr8 job player 2! real nice going..\n") | |
end | |
end | |
end | |
io.write("wanna play again, huh? [y,N]\n") | |
if read_for_y_or_n(false) then | |
io.write("greeeeeeat...\n") | |
io.write("choose new letters? [y,N]\n") | |
choose_letters = read_for_y_or_n(false) | |
else | |
io.write("thanks for playing!\n") | |
break | |
end | |
end | |
end | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
quick note on lua distributions:
mainstream Lua is interpreted
and does not offer the speed or FFI capabilities of its popular fork, Luajit
Luajit can also be interpreted
but can be jit compiled as well
luajit allows for very easy C interop
(which is typically as easy as copy-pasting a header file)
i use luajit which is not 100% compatible with mainstream Lua versions 5.2 or 5.3
yet it is fully compatible with mainstream Lua 5.1
So, to install on your machine
Linux:
I know for a fact Linux Mint and Arch Linux have Luajit in thier repositories
so installing would just require installing from there
For other operating systems/ to build Luajit on your own:
The source can be downloaded from here:
http://luajit.org/install.html
and there are instructions on doing that.
If you don't have Linux and arent interested in building it:
some binaries for mainstream Lua can be found here
http://luabinaries.sourceforge.net/download.html
please download Lua5.1 as i have tested this code with it also
to run:
download/ copy-paste the code into tic_tac_toe.lua
open a terminal and
run luajit (or lua5.1) from the commandline with that file as the second parameter
ex: "luajit tic_tac_toe.lua"
to end the program prematurely, CTRL+C must be pressed twice