Compare commits

...

28 Commits

Author SHA1 Message Date
minecartchris
8641697b4a Add wirelessCode/ccryptolib.md 2026-02-07 16:56:13 -06:00
minecartchris
7a5cca28b1 Add wirelessCode/wireless.lua 2026-02-07 16:55:07 -06:00
minecartchris
eaedfdf5b9 Add wirelessCode/Slot.lua 2026-02-07 16:53:36 -06:00
minecartchris
4aee1a174c Update prog2/slotV2.lua 2026-02-02 15:54:41 -06:00
Herr Katze
b9db35ec9c Fix crash with nil messages 2026-02-01 16:32:03 -08:00
minecartchris
94683e34bf fixed more shit 2026-02-01 17:47:46 -06:00
minecartchris
c4defcd9d9 Fixed tons of shit 2026-02-01 17:34:39 -06:00
bb9a8211f2 Add prog2/slotV2.lua 2026-02-01 18:14:07 -05:00
scmcgowen
ce3e5feffb fix bullshit 2026-02-01 13:25:34 -06:00
minecartchris
6c67a7f2ad One of the rcc admins sent me the code thx alex 2026-02-01 10:46:53 -06:00
minecartchris
ef371883f3 fixed 2026-02-01 01:15:14 -06:00
minecartchris
8b133fae62 added Server code and reqirements 2026-02-01 01:06:46 -06:00
minecartchris
a41dc56329 Add prog2/CardBuilder.lua 2026-02-01 00:34:10 -06:00
minecartchris
33e536c654 Merge pull request 'fix crashes as people are spoons' (#2) from scmcgowen/CC-Casnio:main into main
Reviewed-on: https://git.minecartchris.cc/minecartchris/CC-Casnio/pulls/2
2026-01-31 23:37:05 -06:00
scmcgowen
f697306766 merge upstream 2026-01-31 23:34:25 -06:00
scmcgowen
348919bb52 fix crash 2026-01-31 23:34:06 -06:00
scmcgowen
5b5424cf1d fix crash 2026-01-31 23:33:11 -06:00
minecartchris
851f8b351a Merge pull request 'Fix blackjack not working at all' (#1) from scmcgowen/CC-Casnio:main into main
Reviewed-on: https://git.minecartchris.cc/minecartchris/CC-Casnio/pulls/1
2026-01-31 23:14:20 -06:00
scmcgowen
2a027a4cbe Fix blackjack not working at all 2026-01-31 23:12:19 -06:00
minecartchris
5bf646e4fb Update prog2/Slot.lua 2026-01-31 20:29:07 -06:00
minecartchris
c86cfc3134 Update prog2/BlackJack.lua 2026-01-31 20:28:55 -06:00
minecartchris
c32bd782af Update prog2/Slot.lua 2026-01-31 20:26:21 -06:00
minecartchris
01934f339a Update prog2/ATM.lua 2026-01-05 19:40:42 -06:00
minecartchris
7c0536d0d5 Update prog2/ATM.lua 2026-01-05 19:39:38 -06:00
minecartchris
1f1bdd8a41 Update Casino_install.lua 2026-01-05 07:53:32 -06:00
minecartchris
7853b66d81 Update CasInstV.2.lua 2026-01-04 22:17:49 -06:00
minecartchris
6589028bb6 Update CasInstV.2.lua 2026-01-04 22:17:11 -06:00
minecartchris
3e14ba8eab added nfc programs 2026-01-04 22:09:44 -06:00
16 changed files with 2576 additions and 2 deletions

View File

@@ -1,4 +1,6 @@
local serverPath = "https://git.astronand.dev/minecartchris/CC-Casnio/raw/branch/main/prog"
local branch = "prog"
local serverPath = "https://git.minecartchris.cc/minecartchris/CC-Casnio/raw/branch/main/" .. branch
while true do
if fs.exists("startup.lua") then
print("Would you like to Update the Current Startup File")

70
CasInstV.2.lua.orig Normal file
View File

@@ -0,0 +1,70 @@
local branch = "prog"
<<<<<<< HEAD
local serverPath = "https://git.astronand.dev/minecartchris/CC-Casnio/raw/branch/main/" .. branch
=======
local serverPath = "https://git.minecartchris.cc/minecartchris/CC-Casnio/raw/branch/main/" .. branch
>>>>>>> 7853b66d81f3e9e0b0e9fabcd55e91ec9e3ef172
while true do
if fs.exists("startup.lua") then
print("Would you like to Update the Current Startup File")
local Ans=io.read()
if(Ans=="Yes" or Ans=="yes" or Ans=="y" or Ans=="Y") then
local soft = fs.open("startup.lua", "r")
local data = soft.readLine()
soft.close()
print("file read")
if data == "--ATM" then
fs.delete("startup.lua")
shell.run("wget "..serverPath.."/ATM.lua startup.lua")
elseif data == "--Slot" then
fs.delete("startup.lua")
shell.run("wget "..serverPath.."/Slot.lua startup.lua")
elseif data == "--tic" then
fs.delete("startup.lua")
shell.run("wget "..serverPath.."/ticTackToe.lua startup.lua")
elseif data == "--black" then
fs.delete("startup.lua")
shell.run("wget "..serverPath.."/BlackJack.lua startup.lua")
end
elseif (Ans=="No" or Ans=="no" or Ans=="N" or Ans=="n") then
print("Type Slot, ATM, tic, black jack to install game")
local B=io.read()
if B == "Slot" then
shell.run("wget "..serverPath.."/Slot.lua startup.lua")
break
elseif B == "ATM" then
shell.run("wget "..serverPath.."/ATM.lua startup.lua")
break
elseif B == "tic" then
shell.run("wget "..serverPath.."/ticTackToe.lua startup.lua")
break
elseif B == "black jack" then
shell.run("wget "..serverPath.."/BlackJack.lua startup.lua")
break
else
print("Invalid Input")
end
else
print("Invalid Input")
end
else
print("Type Slot, ATM, tic, black jack to install game")
local B=io.read()
if B == "Slot" then
shell.run("wget "..serverPath.."/Slot.lua startup.lua")
break
elseif B == "ATM" then
shell.run("wget "..serverPath.."/ATM.lua startup.lua")
break
elseif B == "tic" then
shell.run("wget "..serverPath.."/ticTackToe.lua startup.lua")
break
elseif B == "black jack" then
shell.run("wget "..serverPath.."/BlackJack.lua startup.lua")
break
else
print("Invalid Input")
end
end
end

View File

@@ -1,5 +1,6 @@
-- This will install the selected program
local serverPath = "https://git.astronand.dev/minecartchris/CC-Casnio/raw/branch/main/prog"
local branch = "prog"
local serverPath = "https://git.astronand.dev/minecartchris/CC-Casnio/raw/branch/main/" .. branch
if fs.exists("startup.lua") then
print("do you want to update existing file?")
local A = io.read()

96
prog2/ATM.lua Normal file
View File

@@ -0,0 +1,96 @@
--ATM
print("Please insert a cc-casino branded disk!")
--while not fs.exists("/disk/money.lua") do
-- sleep()
--end
print("Would you like to [d]eposit, [w]ithdraw, or check your [b]alance?")
local function interactWithCard(nfc, mode, money)
if mode == "updateBalance" then
nfc.write(tostring(money))
print("Please tap your card to update balance")
while not os.pullEvent("nfc_write") do
sleep(0)
end
end
if mode == "getBalance" then
print("Please tap your card to check balance")
local blank, yes, money = os.pullEvent("nfc_data")
return money
end
end
local nfc = peripheral.wrap("bottom")
local answer = io.read()
--local db = fs.open("/disk2/log.log", "a")
--local id = disk.getID("bottom")
if answer == "d" or answer == "deposit" then
local ironCount = turtle.getItemCount()
--local card = fs.open("/disk/money.lua", "r")
local money = tonumber(interactWithCard(nfc,"getBalance", nil))
local item = turtle.getItemDetail()
if item.name ~= "minecraft:iron_ingot" or item.name == nil then
print("Please insert iron ingots!")
sleep(1)
shell.run("reboot")
end
--card.close()
money = money + ironCount
turtle.drop()
--card = fs.open("/disk/money.lua", "w")
interactWithCard(nfc, "updateBalance", money)
--db.write(ironCount..id.."\n")
--card.close()
print("Your balance is now $"..money)
sleep(2)
elseif answer == "w" or answer == "withdraw" then
print("How much would you like to withdraw?")
answer = tonumber(io.read())
--local card = fs.open("/disk/money.lua", "r")
local money = tonumber(interactWithCard(nfc, "getBalance", nil))
--card.close()
if answer > money then
print("That's more than you have! Try again.")
sleep(2)
else
money = money - answer
print("You now have $"..money)
turtle.suck(answer)
interactWithCard(nfc, "updateBalance", money)
--db.write(answer..id.."\n")
--card = fs.open("/disk/money.lua", "w")
--card.write(money)
--card.close()
sleep(2)
end
elseif answer == "b" or answer == "balance" then
--local card = fs.open("/disk/money.lua", "r")
local money = tonumber(interactWithCard(nfc, "getBalance", nil))
print("Your balance is $"..money)
--card.close()
sleep(2)
end
--db.close()
shell.run("reboot")

179
prog2/BlackJack.lua Normal file
View File

@@ -0,0 +1,179 @@
--black
rednet.open("back")
local function interactWithCard(userUUID, mode, money)
if mode == "updateBalance" then
rednet.broadcast({
uuid = userUUID,
amount = money,
type = "set"
}, "machineBalanceModifier")
end
if mode == "getBalance" then
local _, _, cardUUID = os.pullEvent("nfc_data")
rednet.broadcast({
card = cardUUID
}, "getAccountData")
while true do
local id, message = rednet.receive("server_response", 10)
if not id then
print("the server is down")
print("please ping @minecartchris")
sleep(30)
--shell.run("reboot")
end
if not message then
print("WTF!? I got a rednet message with no data!?")
print("Rebooting...")
sleep(5)
end
if message.type == "account_data" and message.cardId == cardUUID then
local money = message.balance
local playerUUID = message.uuid
local username = message.username
return money, playerUUID, username
end
end
end
end
-- by Jurryteacher67
--local tmp = peripheral.wrap("bottom")
--tmp.ejectDisk()
os.pullEvent= function(...)
while true do
local t = table.pack(os.pullEventRaw(...))
if t[1] ~= "terminate" then
return table.unpack(t,1,t.n)
end
end
end
print("Was Made By Gaurdian15")
if fs.exists("/disk/terminate") then
error("Service mode active",2)
end
shell.run("clear all")
--while not fs.exists("/disk2/money.lua") do
--sleep(0.75)
--print("You do not have a card inserted")
--sleep(2)
--shell.run("clear all")
--end
--print("Please do not remove your card from the drive during games")
local function calculate(win, amount, money)
--local disk = peripheral.wrap("bottom")
--if not disk.isPresent() then
--os.reboot()
--end
if win then
money = money + amount
else
money = money - amount
end
return money
end
print("Was Made By Gaurdian15")
--local money2 = fs.open("/disk2/money.lua", "r")
local money, playerUUID, username = interactWithCard(nil, "getBalance", nil)
--money2.close()
money = tonumber(money)
print("what is your bet?")
local bet = io.read()
bet = tonumber(bet)
if not bet or bet < 20 then
bet = 20
end
if bet > money then
print("you don't have the money required to play")
print("Goodbye")
sleep(5)
os.reboot()
end
pcard1= math.random(1,11)
pcard2= math.random(1,11)
local pcard= pcard1+pcard2
acard1= math.random(1,11)
acard2= math.random(1,11)
local acard=acard1+acard2
while true do
print("Card 1: ",pcard1)
print("Card 2: ",pcard2)
print("Total: ",pcard)
print("")
print("Would you like another card")
print("Y for Yes N for No")
local ans=read()
print(ans)
if(pcard>21) then
print("you Bust")
calculate(n, bet, money)
break
end
if(ans=="Y") then
local anscard= math.random(1,11)
pcard=pcard+anscard
elseif (ans=="N") then
break
else
print("Invalid Input")
end
end
while true do
print("AI Card 1: ",acard1)
print("AI Card 2: ",acard2)
print("AI Total: ",acard)
if(acard<16) then
local aans=math.random(1,11)
acard=aans+acard
print("AI Card",aans)
elseif(acard>=16) then
break
end
end
if(pcard>21) then
money = calculate(false, bet, money)
print("You Busted")
elseif(acard>21) then
money = calculate(true, bet, money)
print("Dealer Bust's")
elseif (pcard>acard) then
moeny = calculate(true, bet, money)
print("You Won")
elseif(acard>pcard) then
money = calculate(false, bet, money)
print("The Dealer won")
elseif(acard==pcard) then
print("Push No One Wins")
end
print("Your new balance is: "..money)
--money2 = fs.open("/disk2/money.lua", "w")
interactWithCard(playerUUID, "updateBalance", money)
--money2.close()
--h = fs.open("disk/house.lua", "w")
--h.write(house)
--h.close()
print("If removing your card do it now")
sleep(5)
os.reboot()

35
prog2/CardBuilder.lua Normal file
View File

@@ -0,0 +1,35 @@
--[[
Casino ATM and Card Creator
Copyright Herr Katze and minecartchris
License: MIT
]]
local nfc = peripheral.find("nfc_reader")
local modem = peripheral.find("modem", function(n,w) return not w.isWireless() end)
rednet.open(peripheral.getName(modem))
local function createCard(cardId)
local timer = os.startTimer(60)
local done = false
nfc.write("casinoAccount_"..cardId, "Casino Card")
while not done do
local ev, id = os.pullEvent()
print(ev)
if ev == "timer" and id == timer then
nfc.cancelWrite()
rednet.broadcast({type="card_timeout"}, "casinoATMC2S")
end
if ev == "nfc_write" then done = true end
end
rednet.broadcast({type="card_created"}, "casinoATMC2S")
end
local function rednetListener()
rednet.host("nfc_atm_write",tostring(os.getComputerID()))
while true do
local id, message =rednet.receive("nfc_atm_write")
createCard(message)
end
end
rednetListener()

455
prog2/Server.lua Normal file
View File

@@ -0,0 +1,455 @@
--[[
Casino Central Server
Copyright 2026 Herr Katze and minecartchris
License: MIT
]]
-- permission function takes uuid as argument
local loop = require("taskmaster")()
local sha256 = require("sha256")
local nfc = peripheral.find("nfc_reader")
local modem = peripheral.find("modem", function(n,w) return not w.isWireless() end)
rednet.open(peripheral.getName(modem))
local permissions = {}
function permissions.all()
return true
end
function permissions.admin(player)
--TODO: check player uuid against configurable admins, currently hardcoded to be Herr Katze
if player == "1f558cbb-0752-49c0-ace4-7f9ed0506fe3" then return true end
if player == "1de578d0-4eae-48db-abc9-7bf3354f809b" then return true end
return false
end
local accounts = {}
--[[
Account format:
{
username = "HerrKatzeGaming",
uuid = "1f558cbb-0752-49c0-ace4-7f9ed0506fe3",
balance = 69420,
validCard = nil, -- either nil for no card, or a random uuid,
banned = false
}
]]
local function saveAccounts()
local data = textutils.serialize(accounts)
local f = fs.open("accounts.slt","w")
f.write(data)
f.close()
end
if not fs.exists("accounts.slt") then
saveAccounts()
end
do
local f = fs.open("accounts.slt","r")
data = f.readAll()
f.close()
accounts = textutils.unserialize(data)
end
local function createAccount(username,uuid,balance)
balance = balance or 0
accounts[uuid] = {
username = username,
uuid = uuid,
balance = balance
}
saveAccounts()
end
local function registerCard(uuid)
local r = http.get("https://www.uuidgenerator.net/api/version4")
local cardId = r.readAll()
r.close()
rednet.broadcast(cardId,"nfc_atm_write")
local id, message = rednet.receive("casinoATMC2S", 61) -- 61 seconds so that the timeout should be handled properly
if not id then
chatbox.tell(uuid, "<red>Did not receive response from ATM, Please ping a casino maintainer</red>", "Chris's Casino", "minimessage")
return
end
if message.type == "card_timeout" then
chatbox.tell(uuid, "<red>Card creation timed out. Re run the command to register your card.</red>", "Chris's Casino", "minimessage")
return
end
if message.type == "card_created" then
accounts[uuid].validCard = cardId
chatbox.tell(uuid, "<green>Card registered.", "Chris's Casino", "minimessage")
saveAccounts()
return
end
print("[ERROR] Received Invalid message type",message.type)
end
local function revokeCard(uuid)
if not accounts[uuid] then
chatbox.tell(uuid,"<red>Cannot revoke card for non-existant account</red>", "Chris's Casino", "minimessage")
return
end
if not accounts[uuid].validCard then
chatbox.tell(uuid,"<red>Card not created or already revoked.</red>", "Chris's Casino", "minimessage")
return
end
accounts[uuid].validCard = nil
saveAccounts()
chatbox.tell(uuid, "<green>Card revoked. use <blue>\\casino register</blue> to obtain a new one. Your balance will transfer to the new card.", "Chris's Casino", "minimessage")
end
local function deleteAccount(uuid)
accounts[uuid] = nil
end
local kromerNode = "https://kromer.reconnected.cc/api/krist"
local pkey = ""
local commands = {}
local function makeaddressbyte(byte)
local byte = 48 + math.floor(byte/7)
return string.char(byte + 39 > 122 and 101 or byte > 57 and byte + 39 or byte)
end
local function make_address(key)
local protein = {}
local stick = sha256(sha256(key))
local n = 0
local link = 0
local v2 = "k"
repeat
if n<9 then protein[n] = string.sub(stick,0,2)
stick = sha256(sha256(stick)) end
n = n+1
until n==9
n=0
repeat
link = tonumber(string.sub(stick,1+(2*n),2+(2*n)),16) % 9
if string.len(protein[link]) ~= 0 then
v2 = v2 .. makeaddressbyte(tonumber(protein[link],16))
protein[link] = ''
n=n+1
else
stick = sha256(stick)
end
until n==9
return v2
end
local function split(inputstr, sep)
sep = sep or ","
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
local address = make_address(pkey)
print(address)
local function handleWebSockets()
local id = -1
local r,f = http.post(kromerNode.."/ws/start","{\"privatekey\":\""..pkey.."\"}",{["content-type"]="application/json"})
local resp = textutils.unserialiseJSON(r.readAll())
r.close()
r = nil
if resp.ok then
socket = http.websocket(resp.url)
print("Connected to Krist Websockets")
id = id + 1
socket.send('{\"id\":'..id ..',\"type\":\"subscribe\",\"event\":\"ownTransactions\"}')
while true do
event = {os.pullEvent()}
if event[1] == "websocket_message" then
if event[2] == resp.url then
wsevent = textutils.unserialiseJSON(event[3])
if wsevent.event == "transaction" and wsevent.transaction.to == address then
local from = wsevent.transaction.from
local hasMessage = false
local hasError = false
local hasUUID = false
local otherUUID = nil
err = ""
if wsevent.transaction.metadata then
mta = split(wsevent.transaction.metadata,";")
for i,p in pairs(mta) do
if p:match("useruuid") and not hasUUID then
otherUUID = split(p,"=")[2]
hasUUID = true
end
end
end
print(otherUUID)
if not otherUUID then
os.queueEvent("make_transaction",wsevent.transaction.from,wsevent.transaction.value)
else
if not accounts[otherUUID] then
chatbox.tell(otherUUID,"<red>Player doesn't have an account.", "Chris's Casino", "minimessage")
os.queueEvent("make_transaction",wsevent.transaction.from,wsevent.transaction.value)
else
accounts[otherUUID].balance = accounts[otherUUID].balance + wsevent.transaction.value
chatbox.tell(otherUUID,"<green>Added <blue>"..wsevent.transaction.value.."</blue> to your balance", "Chris's Casino", "minimessage")
saveAccounts()
end
end
elseif wsevent.type == "keepalive" or wsevent.type == "response" then
else
end
end
elseif event[1] == "make_transaction" then
id = id + 1
local rq = {
id = id,
type="make_transaction",
to = event[2],
amount = event[3],
metadata = event[4],
}
socket.send(textutils.serialiseJSON(rq))
local c
repeat
c = socket.receive()
c = textutils.unserialiseJSON(c)
until c.type == "response"
os.queueEvent("transaction_complete",c.ok)
end
end
end
end
commands.balance = {
exec= function(name, uuid, args)
if accounts[uuid] and accounts[uuid].banned then
chatbox.tell(uuid,"<red>You have been banned from Chris's Casino, Please contact a casino maintainer for a balance refund.", "Chris's Casino", "minimessage")
return
end
if #args == 0 or not permissions.admin(uuid) then
if not accounts[uuid] then
chatbox.tell(name,"<red>You don't have an account, use <blue>\\casino register</blue> to get one", "Chris's Casino", "minimessage")
return
end
chatbox.tell(name,"<green>Your balance is <blue>"..accounts[uuid].balance.."</blue>", "Chris's Casino", "minimessage")
else
local otherUUID = args[1]
if not accounts[otherUUID] then
chatbox.tell(name,"<red>Player doesn't have an account.", "Chris's Casino", "minimessage")
return
end
chatbox.tell(name,"<green>"..accounts[otherUUID].username.."'s balance is <blue>"..accounts[otherUUID].balance.."</blue>", "Chris's Casino", "minimessage")
end
end,
permission = permissions.all
}
commands.withdraw = {
exec = function(name,uuid,args)
if accounts[uuid] and accounts[uuid].banned then
chatbox.tell(uuid,"<red>You have been banned from Chris's Casino, Please contact a casino maintainer for a balance refund.", "Chris's Casino", "minimessage")
return
end
if not accounts[uuid] then
chatbox.tell(name,"<red>You don't have an account, use <blue>\\casino register</blue> to get one", "Chris's Casino", "minimessage")
return
end
if args[1] then
local response = http.get(("https://kromer.reconnected.cc/api/v1/wallet/by-name/%s"):format(name))
response = textutils.unserializeJSON(response.readAll())
local address = response.data[1].address
local amount = math.min(tonumber(args[1]),accounts[uuid].balance)
print(amount)
if amount == 0 then
chatbox.tell(name,"<red>You have no money.</red>","Chris's Casino","minimessage")
else
accounts[uuid].balance = accounts[uuid].balance - amount
saveAccounts()
os.queueEvent("make_transaction",address,amount)
chatbox.tell(name,"<red>Withdrew <blue>"..amount.."kro </blue> from your balance. You have <blue>"..accounts[uuid].balance.."</blue> remaining.", "Chris's Casino", "minimessage")
end
end
end,
permission = permissions.all
}
commands.bal = commands.balance -- alias for \casino bal
commands.register = {
exec = function(name, uuid, args)
if accounts[uuid] and accounts[uuid].banned then
chatbox.tell(uuid,"<red>You have been banned from Chris's Casino, Please contact a casino maintainer for a balance refund.", "Chris's Casino", "minimessage")
return
end
if accounts[uuid] and accounts[uuid].validCard then
chatbox.tell(name,"<green>You already have a registered card, use <blue>\\casino revoke</blue> to revoke it, then create a new one with <blue>\\casino register</blue>","Chris's Casino", "minimessage")
return
end
if not accounts[uuid] then createAccount(name,uuid) end
chatbox.tell(name,"<green>Creating card, tap on the NFC reader to register it. This card request will expire in 60s if not registered.", "Chris's Casino", "minimessage")
registerCard(uuid)
end,
permission = permissions.all
}
commands.revoke = {
exec = function(name, uuid, args)
if accounts[uuid] and accounts[uuid].banned then
chatbox.tell(uuid,"<red>You have been banned from Chris's Casino, Please contact a casino maintainer for a balance refund.", "Chris's Casino", "minimessage")
return
end
revokeCard(uuid)
end,
permission = permissions.all
}
commands.ban = {
exec = function(name, uuid, args)
local account = args[1]
if not accounts[account] then
createAccount("$unknown",uuid)
end
if accounts[account].banned then
chatbox.tell(name,"<red>User is already banned.", "Chris's Casino", "minimessage")
return
end
accounts[account].banned = true
chatbox.tell(name,"<green>Banned user with uuid "..account, "Chris's Casino", "minimessage")
end,
permission = permissions.admin
}
commands.pardon = {
exec = function(name, uuid, args)
local account = args[1]
if not accounts[account] or not accounts[account].banned then
chatbox.tell(name,"<red>User is not banned.", "Chris's Casino", "minimessage")
return
end
accounts[account].banned = false
if accounts[account].name == "$unknown" then deleteAccount(account) end -- Delete anonymous banned users.
chatbox.tell(name,"<green>Pardoned user with uuid "..account, "Chris's Casino", "minimessage")
end,
permission = permissions.admin
}
commands.add = {
exec = function(name, uuid, args)
if not args[2] then
chatbox.tell(name,"<red>Both a player UUID and a number must be provided", "Chris's Casino", "minimessage")
return
end
local otherUUID = args[1]
if not accounts[otherUUID] then
chatbox.tell(name,"<red>Player doesn't have an account.", "Chris's Casino", "minimessage")
return
end
accounts[otherUUID].balance = accounts[otherUUID].balance + tonumber(args[2])
chatbox.tell(name,"<green>Added <blue>"..args[2].."</blue> To "..accounts[otherUUID].username.."'s balance", "Chris's Casino", "minimessage")
saveAccounts()
end,
permission = permissions.admin
}
commands.subtract = {
exec = function(name, uuid, args)
local otherUUID = args[1]
if not args[2] then
chatbox.tell(name,"<red>Both a player UUID and a number must be provided", "Chris's Casino", "minimessage")
return
end
if not accounts[otherUUID] then
chatbox.tell(name,"<red>Player doesn't have an account.", "Chris's Casino", "minimessage")
return
end
accounts[otherUUID].balance = accounts[otherUUID].balance - tonumber(args[2])
chatbox.tell(name,"<green>Subtracted <blue>"..args[2].."</blue> From "..accounts[otherUUID].username.."'s balance", "Chris's Casino", "minimessage")
saveAccounts()
end,
permission = permissions.admin
}
commands.setbal = {
exec = function(name, uuid, args)
local otherUUID = args[1]
if not args[2] then
chatbox.tell(name,"<red>Both a player UUID and a number must be provided", "Chris's Casino", "minimessage")
return
end
if not accounts[otherUUID] then
chatbox.tell(name,"<red>Player doesn't have an account.", "Chris's Casino", "minimessage")
return
end
accounts[otherUUID].balance = tonumber(args[2])
chatbox.tell(name,"<green>Set"..accounts[otherUUID].username.."'s balance to <blue>"..args[2].."</blue>", "Chris's Casino", "minimessage")
saveAccounts()
end,
permission = permissions.admin
}
local function commandHandler()
while true do
_, user, command, args, data = os.pullEvent("command")
if command ~= "casino" then goto notOurCommand end
local subcommand = table.remove(args,1)
if not commands[subcommand] then
chatbox.tell(user,"<red>Invalid subcommand.</red>", "Chris's Casino", "minimessage")
goto continue
end
do
local uuid = data.user.uuid
if not commands[subcommand].permission(uuid) then
chatbox.tell(user,"<red>You do not have permission to run this command", "Chris's Casino", "minimessage")
goto continue
end
loop:addFunction(commands[subcommand].exec,user,uuid,args)
end
::continue::
if accounts[data.user.uuid] and accounts[data.user.uuid].username ~= user then
accounts[data.user.uuid].username = user
chatbox.tell(user,"<green> Your username has been updated in the account database.", "Chris's Casino", "minimessage")
saveAccounts()
end
::notOurCommand:: -- separate label so we don't respond to other people's commands with a username change.
end
end
local function rednetMessageHandler()
while true do
local id, message, protocol = rednet.receive()
if protocol == "machineBalanceModifier" then
if type(message) ~= "table" or not message.uuid or not message.amount then goto continue_rednet end -- Guard against bullshit messages
if message.type == "add" then
accounts[message.uuid].balance = accounts[message.uuid].balance + message.amount
end
if message.type == "subtract" then
accounts[message.uuid].balance = accounts[message.uuid].balance + message.amount
end
if message.type == "set" then
accounts[message.uuid].balance = message.amount
end
elseif protocol == "getAccountData" then
if type(message) ~= "table" or not message.card then goto continue_rednet end
for _, account in pairs(accounts) do
if "casinoAccount_"..account.validCard == message.card then -- Here's our guy!
rednet.send(id,{
type = "account_data",
uuid = account.uuid,
username = account.username,
balance = account.balance,
cardId = message.card
},"server_response")
break
end
end
end
::continue_rednet::
end
end
loop:task(commandHandler)
:task(rednetMessageHandler)
:task(handleWebSockets)
:run()

129
prog2/Slot.lua Normal file
View File

@@ -0,0 +1,129 @@
--Slot
rednet.open("back")
local function interactWithCard(userUUID, mode, money)
if mode == "updateBalance" then
rednet.broadcast({
uuid = userUUID,
amount = money,
type = "set"
}, "machineBalanceModifier")
end
if mode == "getBalance" then
local _, _, cardUUID = os.pullEvent("nfc_data")
rednet.broadcast({
card = cardUUID
}, "getAccountData")
while true do
local id, message = rednet.receive("server_response", 10)
if not id then
print("the server is down")
print("please ping @minecartchris")
sleep(30)
--shell.run("reboot")
end
if not message then
print("WTF!? I got a rednet message with no data!?")
print("Rebooting...")
sleep(5)
end
if message.type == "account_data" and message.cardId == cardUUID then
local money = message.balance
local playerUUID = message.uuid
local username = message.username
return money, playerUUID, username
end
end
end
end
sleep(0.25)
nfc = peripheral.wrap("bottom")
os.pullEvent= function(...)
while true do
local t = table.pack(os.pullEventRaw(...))
if t[1] ~= "terminate" then
return table.unpack(t,1,t.n)
end
end
end
if fs.exists("/disk/terminate") then
error("Service mode active",2)
end
modem = peripheral.wrap("back")
shell.run("clear all")
--while not fs.exists("/disk2/money.lua") do
--sleep(0.75)
--print("You do not have a card inserted")
--sleep(2)
--shell.run("clear all")
--end
--print("Please do not remove your card from the drive during games")
local money = " "
local winner = false
local randnum = 0
local bet = 0
--local money2 = fs.open("/disk2/money.lua", "r")
print("Welcome to the Slot Machine!")
print("Please swipe your card to begin")
--local _, _, userUUID = os.pullEvent("nfc_data")
money, playerUUID, username = interactWithCard(nil, "getBalance", nil)
--money2.close()
print("Welcome "..tostring(username))
local h = fs.open("disk/house.lua", "r")
house = h.readAll()
h.close()
print("$",money)
money = tonumber(money)
print("what is your bet?")
bet = tonumber(io.read())
print("what is your guess 1 to 15?")
userGess = tonumber(io.read())
if not bet or bet > money or bet < 0 then
print("You do not have enough funds or did not enter a bet.")
sleep(3)
shell.run("reboot")
end
randnum = tonumber(math.random(0, 14) + 1)
if userGess == randnum then
winner = true
end
house = tonumber(house)
if not winner then
print("you lost ;(")
print("The correct number was", randnum)
money = money - bet
house = house + bet
print("you have $",money, "left over")
interactWithCard(playerUUID, "updateBalance", money)
end
if winner then
bet = bet * 2
money = bet + money
print("You win!!!!!")
house = house - bet
print("You now have $", money)
interactWithCard(playerUUID, "updateBalance", money)
end
--money2 = fs.open("/disk2/money.lua", "w")
--money2.close()
h = fs.open("disk/house.lua", "w")
h.write(house)
h.close()
--print("If removing your card do it now")
sleep(2)
os.reboot()

66
prog2/sendkromer.lua Normal file
View File

@@ -0,0 +1,66 @@
-- Load private key
local keyFile = fs.open("private.key", "r")
if not keyFile then
print("Private key file not found.")
return
end
local privateKey = keyFile.readAll()
keyFile.close()
write("Recipient Kromer address: ")
local to = read()
write("Amount to send (in KST): ")
local amountInput = read()
local amount = tonumber(amountInput)
if not amount or amount <= 0 then
print("Invalid amount.")
return
end
write("Metadata (optional): ")
local metadata = read()
local payload = {
amount = amount,
to = to,
metadata = metadata ~= "" and metadata or nil,
privatekey = privateKey
}
local url = "https://kromer.reconnected.cc/api/krist/transactions"
local headers = {
["Content-Type"] = "application/json"
}
local json = textutils.serializeJSON(payload)
print("Sending transaction to Kromer API...")
local response = http.post(url, json, headers)
if not response then
print("Failed to contact Kromer API.")
return
end
local result = response.readAll()
response.close()
local success, data = pcall(textutils.unserializeJSON, result)
if not success then
print("Error parsing response: " .. result)
return
end
if data.error then
print("Transaction failed: " .. data.error)
else
print("Transaction successful!")
if data.transaction and data.transaction.txid then
print("TX ID: " .. data.transaction.txid)
else
print("No TX ID returned. Raw transaction data:")
print(textutils.serialize(data.transaction))
end
end

3
prog2/sha256.lua Normal file
View File

@@ -0,0 +1,3 @@
local g = string.gsub
sha256 = loadstring(g(g(g(g(g(g(g(g('Sa=XbandSb=XbxWSc=XlshiftSd=unpackSe=2^32SYf(g,h)Si=g/2^hSj=i%1Ui-j+j*eVSYk(l,m)Sn=l/2^mUn-n%1VSo={0x6a09e667Tbb67ae85T3c6ef372Ta54ff53aT510e527fT9b05688cT1f83d9abT5be0cd19}Sp={0x428a2f98T71374491Tb5c0fbcfTe9b5dba5T3956c25bT59f111f1T923f82a4Tab1c5ed5Td807aa98T12835b01T243185beT550c7dc3T72be5d74T80deb1feT9bdc06a7Tc19bf174Te49b69c1Tefbe4786T0fc19dc6T240ca1ccT2de92c6fT4a7484aaT5cb0a9dcT76f988daT983e5152Ta831c66dTb00327c8Tbf597fc7Tc6e00bf3Td5a79147T06ca6351T14292967T27b70a85T2e1b2138T4d2c6dfcT53380d13T650a7354T766a0abbT81c2c92eT92722c85Ta2bfe8a1Ta81a664bTc24b8b70Tc76c51a3Td192e819Td6990624Tf40e3585T106aa070T19a4c116T1e376c08T2748774cT34b0bcb5T391c0cb3T4ed8aa4aT5b9cca4fT682e6ff3T748f82eeT78a5636fT84c87814T8cc70208T90befffaTa4506cebTbef9a3f7Tc67178f2}SYq(r,q)if e-1-r[1]<q then r[2]=r[2]+1;r[1]=q-(e-1-r[1])-1 else r[1]=r[1]+qVUrVSYs(t)Su=#t;t[#t+1]=0x80;while#t%64~=56Zt[#t+1]=0VSv=q({0,0},u*8)fWw=2,1,-1Zt[#t+1]=a(k(a(v[w]TFF000000),24)TFF)t[#t+1]=a(k(a(v[w]TFF0000),16)TFF)t[#t+1]=a(k(a(v[w]TFF00),8)TFF)t[#t+1]=a(v[w]TFF)VUtVSYx(y,w)Uc(y[w]W0,24)+c(y[w+1]W0,16)+c(y[w+2]W0,8)+(y[w+3]W0)VSYz(t,w,A)SB={}fWC=1,16ZB[C]=x(t,w+(C-1)*4)VfWC=17,64ZSD=B[C-15]SE=b(b(f(B[C-15],7),f(B[C-15],18)),k(B[C-15],3))SF=b(b(f(B[C-2],17),f(B[C-2],19)),k(B[C-2],10))B[C]=(B[C-16]+E+B[C-7]+F)%eVSG,h,H,I,J,j,K,L=d(A)fWC=1,64ZSM=b(b(f(J,6),f(J,11)),f(J,25))SN=b(a(J,j),a(Xbnot(J),K))SO=(L+M+N+p[C]+B[C])%eSP=b(b(f(G,2),f(G,13)),f(G,22))SQ=b(b(a(G,h),a(G,H)),a(h,H))SR=(P+Q)%e;L,K,j,J,I,H,h,G=K,j,J,(I+O)%e,H,h,G,(O+R)%eVA[1]=(A[1]+G)%e;A[2]=(A[2]+h)%e;A[3]=(A[3]+H)%e;A[4]=(A[4]+I)%e;A[5]=(A[5]+J)%e;A[6]=(A[6]+j)%e;A[7]=(A[7]+K)%e;A[8]=(A[8]+L)%eUAVUY(t)t=t W""t=type(t)=="string"and{t:byte(1,-1)}Wt;t=s(t)SA={d(o)}fWw=1,#t,64ZA=z(t,w,A)VU("%08x"):rep(8):format(d(A))V',"S"," local "),"T",",0x"),"U"," return "),"V"," end "),"W","or "),"X","bit32."),"Y","function "),"Z"," do "))()
return sha256

174
prog2/slotV2.lua Normal file
View File

@@ -0,0 +1,174 @@
--slot2
rednet.open("back")
local function interactWithCard(userUUID, mode, money)
if mode == "updateBalance" then
rednet.broadcast({
uuid = userUUID,
amount = money,
type = "set"
}, "machineBalanceModifier")
end
if mode == "getBalance" then
local _, _, cardUUID = os.pullEvent("nfc_data")
rednet.broadcast({
card = cardUUID
}, "getAccountData")
while true do
local id, message = rednet.receive("server_response", 10)
if not id then
print("the server is down")
print("please ping @minecartchris")
sleep(30)
--shell.run("reboot")
end
if not message then
print("WTF!? I got a rednet message with no data!?")
print("Rebooting...")
sleep(5)
end
if message.type == "account_data" and message.cardId == cardUUID then
local money = message.balance
local playerUUID = message.uuid
local username = message.username
return money, playerUUID, username
end
end
end
end
os.pullEvent= function(...)
while true do
local t = table.pack(os.pullEventRaw(...))
if t[1] ~= "terminate" then
return table.unpack(t,1,t.n)
end
end
end
if fs.exists("/disk/terminate") then
error("Service mode active",2)
end
math.randomseed(os.epoch("utc"))
for i = 1, 5 do math.random() end
local function random(min, max)
return math.random(min, max)
end
local function input(message)
local w, h = term.getSize()
term.setCursorPos(1, h)
term.clearLine()
io.write(message)
return io.read()
end
local function calculate_winnings(got, b)
--local b = tonumber(bet) or 0
if got[1] == got[2] and got[2] == got[3] then
return b * 10
elseif got[1] == got[2] or got[2] == got[3] or got[1] == got[3] then
return b
else
return 0
end
end
local function draw()
local letters = {'', '', '', ' '}
local got = {}
for i = 1, 3 do
table.insert(got, letters[random(1, #letters)])
end
return got
end
local function draw_display(display)
local w, h = term.getSize()
local midW = math.floor(w / 2)
local midH = math.floor(h / 2)
term.clear()
term.setCursorPos(midW - 5, midH - 1)
print("+-----------+")
term.setCursorPos(midW - 5, midH)
print("| " .. (display[1] or "-") .. " | " .. (display[2] or "-") .. " | " .. (display[3] or "-") .. " |")
term.setCursorPos(midW - 5, midH + 1)
print("+-----------+")
end
local function spin(current_got)
local letters = {'', '', '', ' '}
local delay = 0.05
for i = 1, 12 do
local display = {}
for j = 1, 3 do
if current_got[j] then
display[j] = current_got[j]
else
display[j] = letters[random(1, #letters)]
end
end
draw_display(display)
sleep(delay)
if i > 6 then
delay = delay + 0.05
end
end
end
local function run()
term.clear()
print("Welcome to the Slot Machine!")
print("Please swipe your card to begin")
money, playerUUID, username = interactWithCard(nil, "getBalance", nil)
term.clear()
print("Welcome ".. username .." have fun!")
local bet_input = tonumber(input("Bet: "))
if money < bet_input then
print("please get more money or bet less as you can't bet more then you have")
return
end
local final = draw()
local current = {nil, nil, nil}
for i = 1, 3 do
spin(current)
current[i] = final[i]
draw_display(current)
sleep(0.5)
end
local winnings = calculate_winnings(final, bet_input)
local w, h = term.getSize()
term.setCursorPos(math.floor(w/2) - 6, math.floor(h/2) + 3)
money = money + winnings
interactWithCard(playerUUID, "updateBalance", money)
print("WON: " .. winnings)
for i = 1, 4 do
sleep(0.3)
term.setCursorPos(math.floor(w/2) - 5, math.floor(h/2))
term.write(" ")
sleep(0.3)
draw_display(final)
end
sleep(30)
end
shell.execute("clear")
while true do
run()
end

747
prog2/taskmaster.lua Normal file
View File

@@ -0,0 +1,747 @@
-- Taskmaster: A simple and highly flexible task runner/coroutine manager for ComputerCraft
-- Supports adding/removing tasks, early exits for tasks, event white/blacklists, automatic
-- terminal redirection, task pausing, promises, and more.
-- Made by JackMacWindows
-- Licensed under CC0 in the public domain
--[[
Examples:
- Run three functions in parallel, and wait for any to exit.
require("taskmaster")(
func1, func2, func3
):waitForAny()
- Run three functions in parallel, and wait for all to exit.
require("taskmaster")(
func1, func2, func3
):waitForAll()
- Builder-style creation of three event listeners for keyboard events.
require("taskmaster")()
:eventListener("key", function(ev, key) print("Key:", keys.getName(key)) end)
:eventListener("key_up", function(ev, key) print("Key up:", keys.getName(key)) end)
:eventListener("char", function(ev, char) print("Character:", char) end)
:run()
- Create a loop with two background tasks (which don't receive user interaction events) and one foreground task.
The foreground task may exit itself if a specific character is pressed.
local loop = require("taskmaster")()
loop:setEventBlacklist {"key", "key_up", "char", "paste", "mouse_click", "mouse_up", "mouse_scroll", "mouse_drag"}
loop:addTask(bgFunc)
loop:addTimer(2, pollingFunction)
local function fgFunc(task)
while true do
local event, p1 = os.pullEvent()
if event == "char" and p1 == "q" then
task:remove()
end
end
end
local task = loop:addTask(fgFunc)
task:setEventBlacklist {}
task:setPriority(10)
loop:run()
- Fetch a remote JSON resource in parallel using promises.
local loop = require("taskmaster")()
local function main()
loop.Promise.fetch("https://httpbin.org/headers")
:next(function(handle) return handle.json() end)
:next(function(data) print(data.headers["User-Agent"]) end)
:catch(printError)
end
loop:task(main):run()
]]
local expect = require "cc.expect"
---@class Task
---@field master Taskmaster The event loop for the task
local Task = {}
local Task_mt = {__name = "Task", __index = Task}
--- Pauses the task, preventing it from running. This will yield if the task calls this method on itself.
function Task:pause()
self.paused = true
if self.master.currentTask == self then coroutine.yield() end
end
--- Unpauses the task if it was previously paused by @{Task.pause}.
function Task:unpause()
self.paused = false
end
--- Removes the task from the run loop, as if it returned. This will yield if the task calls this method on itself.
function Task:remove()
self.master.dead[#self.master.dead+1] = self
self.paused = true
if self.master.currentTask == self then coroutine.yield() end
end
--- Sets the priority of the task. This determines the order tasks are run in.
---@param priority number The priority of the task (0 is the default)
function Task:setPriority(priority)
expect(1, priority, "number")
self.priority = priority
self.master.shouldSort = true
end
--- Sets a blacklist for events to send to this task.
---@param list? string[] A list of events to not send to this task
function Task:setEventBlacklist(list)
if expect(1, list, "table", "nil") then
self.blacklist = {}
for _, v in ipairs(list) do self.blacklist[v] = true end
else self.blacklist = nil end
end
--- Sets a whitelist for events to send to this task.
---@param list? string[] A list of events to send to this task (others are discarded)
function Task:setEventWhitelist(list)
if expect(1, list, "table", "nil") then
self.whitelist = {}
for _, v in ipairs(list) do self.whitelist[v] = true end
else self.whitelist = nil end
end
--- Sets an error handler for a task.
---@param errh? fun(err: any, task: Task) A function to call if the task throws an error
function Task:setErrorHandler(errh)
self.errh = expect(1, errh, "function", "nil")
end
---@class Promise
---@field private task Task
---@field private resolve fun(...: any)|nil
---@field private reject fun(err: any)|nil
---@field private final fun()|nil
local Promise = {}
local Promise_mt = {__name = "Promise", __index = Promise}
--- Creates a new Promise on the selected run loop.
---@param loop Taskmaster The loop to create the promise on
---@param fn fun(resolve: fun(...: any), reject: fun(err: any)) The main function for the promise
---@return Promise promise The new promise
function Promise:new(loop, fn)
expect(1, loop, "table")
expect(2, fn, "function")
local obj = setmetatable({}, Promise_mt)
obj.task = loop:addTask(function()
local ok, err = pcall(fn,
function(...) if obj.resolve then return obj.resolve(...) end end,
function(err)
while obj do
if obj.reject then return obj.reject(err) end
obj = obj.next_promise
end
end
)
if not ok and obj.reject then obj.reject(err) end
end)
return obj
end
--- Creates a new Promise that resolves once all of the listed promises resolve.
---@param loop Taskmaster The loop to create the promise on
---@param list Promise[] The promises to wait for
---@return Promise promise The new promise
function Promise:all(loop, list)
expect(1, loop, "table")
expect(2, list, "table")
return Promise:new(loop, function(resolve, reject)
local count = 0
for _, v in ipairs(list) do
v:next(function(...)
count = count + 1
if count == #list then resolve(...) end
end, reject)
end
end)
end
--- Creates a new Promise that resolves once any of the listed promises resolve, or rejects if all promises reject.
---@param loop Taskmaster The loop to create the promise on
---@param list Promise[] The promises to wait for
---@return Promise promise The new promise
function Promise:any(loop, list)
expect(1, loop, "table")
expect(2, list, "table")
return Promise:new(loop, function(resolve, reject)
local count = 0
for _, v in ipairs(list) do
v:next(resolve, function(err)
count = count + 1
if count == #list then reject(err) end
end)
end
end)
end
--- Creates a new Promise that resolves once any of the listed promises resolve.
---@param loop Taskmaster The loop to create the promise on
---@param list Promise[] The promises to wait for
---@return Promise promise The new promise
function Promise:race(loop, list)
expect(1, loop, "table")
expect(2, list, "table")
return Promise:new(loop, function(resolve, reject)
for _, v in ipairs(list) do v:next(resolve, reject) end
end)
end
--- Creates a new Promise that immediately resolves to a value.
---@param loop Taskmaster The loop to create the promise on
---@param val any The value to resolve to
---@return Promise promise The new promise
function Promise:_resolve(loop, val)
expect(1, loop, "table")
local obj = setmetatable({}, Promise_mt)
obj.task = loop:addTask(function()
if obj.resolve then obj.resolve(val) end
end)
return obj
end
--- Creates a new Promise that immediately rejects with an error.
---@param loop Taskmaster The loop to create the promise on
---@param err any The value to resolve to
---@return Promise promise The new promise
function Promise:_reject(loop, err)
expect(1, loop, "table")
local obj = setmetatable({}, Promise_mt)
obj.task = loop:addTask(function()
if obj.reject then obj.reject(err) end
end)
return obj
end
--- Adds a function to call when the promise resolves.
---@param fn fun(...: any): Promise|nil The function to call
---@param err? fun(err: any) A function to catch errors
---@return Promise next The next promise in the chain
function Promise:next(fn, err)
expect(1, fn, "function")
expect(2, err, "function", "nil")
self.resolve = function(...)
self.resolve = nil
local res = fn(...)
if self.next_promise then
if type(res) == "table" and getmetatable(res) == Promise_mt then
for k, v in pairs(self.next_promise) do res[k] = v end
self.next_promise = res
else
self.next_promise.resolve(res)
end
end
if self.final then self.final() end
end
if err then self.reject = function(v) self.reject = nil err(v) if self.final then self.final() end end end
self.next_promise = setmetatable({}, Promise_mt)
return self.next_promise
end
Promise.Then = Promise.next
--- Sets the error handler for the promise.
---@param fn fun(err: any) The error handler to use
---@return Promise self
function Promise:catch(fn)
expect(1, fn, "function")
self.reject = function(err) self.reject = nil fn(err) if self.final then self.final() end end
return self
end
--- Sets a function to call after the promise settles.
---@param fn fun() The function to call
---@return Promise self
function Promise:finally(fn)
expect(1, fn, "function")
self.final = function() self.final = nil return fn() end
return self
end
---@diagnostic disable: missing-return
---@class PromiseConstructor
local PromiseConstructor = {}
--- Creates a new Promise on the selected run loop.
---@param fn fun(resolve: fun(...: any), reject: fun(err: any)) The main function for the promise
---@return Promise promise The new promise
function PromiseConstructor.new(fn) end
--- Creates a new Promise that resolves once all of the listed promises resolve.
---@param list Promise[] The promises to wait for
---@return Promise promise The new promise
function PromiseConstructor.all(list) end
--- Creates a new Promise that resolves once any of the listed promises resolve, or rejects if all promises reject.
---@param list Promise[] The promises to wait for
---@return Promise promise The new promise
function PromiseConstructor.any(list) end
--- Creates a new Promise that resolves once any of the listed promises resolve.
---@param list Promise[] The promises to wait for
---@return Promise promise The new promise
function PromiseConstructor.race(list) end
--- Creates a new Promise that immediately resolves to a value.
---@param val any The value to resolve to
---@return Promise promise The new promise
function PromiseConstructor.resolve(val) end
--- Creates a new Promise that immediately rejects with an error.
---@param err any The value to resolve to
---@return Promise promise The new promise
function PromiseConstructor.reject(err) end
--- Makes an HTTP request to a URL, and returns a Promise for the result.
--- The promise will resolve with the handle to the response, which will also
--- have the following methods:
--- - res.text(): Returns a promise that resolves to the body of the response.
--- - res.table(): Returns a promise that resolves to the body unserialized as a Lua table.
--- - res.json(): Returns a promise that resolves to the body unserialized as JSON.
---@param url string The URL to connect to
---@param body? string If specified, a POST body to send
---@param headers? table<string, string> Any HTTP headers to add to the request
---@param binary? boolean Whether to send in binary mode (deprecated as of CC:T 1.109.0)
---@overload fun(options: {url: string, body?: string, headers?: string, method?: string, binary?: string, timeout?: number}): Promise
---@return Promise promise The new promise
function PromiseConstructor.fetch(url, body, headers, binary) end
---@class Queue
---@field private loop Taskmaster
---@field private head number
---@field private tail number
---@field private waiting table<Task, boolean>
---@field private currentAwait any
---@field private lastAwait any
local Queue = {}
local Queue_mt = {__name = "Queue", __index = Queue}
--- Returns the length of the queue.
---@return number length The length of the queue
function Queue:length()
return self.tail - self.head
end
Queue_mt.__len = Queue.length
--- Returns whether the queue is empty.
---@return boolean empty Whether the queue is empty
function Queue:empty()
return self.head == self.tail
end
--- Returns the item in the front of the queue, or nil if the queue is empty.
---@return any|nil item The head of the queue
function Queue:peek()
return self[self.head]
end
--- Pushes an item to the end of the queue. This will safely awaken any tasks
--- that are awaiting this queue. Note that if multiple tasks are awaiting the
--- queue, only one of them will pop this item - if more items are pushed, the
--- other tasks may pop those, otherwise they will continue waiting.
---@param item any The item to push
function Queue:push(item)
self[self.tail] = item
self.tail = self.tail + 1
if next(self.waiting) and self.currentAwait ~= self.lastAwait then
os.queueEvent("taskmaster_queue_" .. tostring(self))
self.lastAwait = self.currentAwait
end
end
--- Returns the next item in the queue and removes it. If the queue is empty,
--- the task waits for an item to be pushed. Note that if multiple tasks are
--- awaiting the queue, this may not always return the *next* item, as another
--- task may pop it before this task runs.
---
--- This must be called by a task in the owning loop.
---@return any item The item that was popped
function Queue:pop()
while self.head == self.tail do
if self.loop.currentTask == nil then error("This function must be called inside a running task", 2) end
self.waiting[self.loop.currentTask] = true
self.currentAwait = {}
os.pullEvent("taskmaster_queue_" .. tostring(self))
self.waiting[self.loop.currentTask] = nil
end
local retval = self[self.head]
self[self.head] = nil
self.head = self.head + 1
return retval
end
-- TODO: Multi queues should probably be able to share events. This'll break for
-- more than 256 tasks sharing a multiqueue.
---@class MultiQueue
---@field private loop Taskmaster
---@field private queues table<Task, Queue>
local MultiQueue = {}
local MultiQueue_mt = {__name = "MultiQueue", __index = MultiQueue}
--- Initializes a queue for the current task, allowing items to be pushed for
--- this task. This is called automatically by `pop` as well.
---
--- This must be called by a task in the owning loop.
function MultiQueue:init()
if not self.queues[self.loop.currentTask] then
self.queues[self.loop.currentTask] = self.loop:createQueue()
end
end
--- Pushes an item to the end of all queues. This will safely awaken any tasks
--- that are awaiting this queue.
---@param item any The item to push
function MultiQueue:push(item)
for _, v in pairs(self.queues) do v:push(item) end
end
--- Returns the next item in the queue and removes it. If the queue is empty,
--- the task waits for an item to be pushed.
---
--- This must be called by a task in the owning loop.
---@return any item The item that was popped
function MultiQueue:pop()
local q = self.queues[self.loop.currentTask]
if not q then
q = self.loop:createQueue()
self.queues[self.loop.currentTask] = q
end
return q:pop()
end
---@diagnostic enable: missing-return
---@class Taskmaster
---@field Promise PromiseConstructor
local Taskmaster = {}
local Taskmaster_mt = {__name = "Taskmaster", __index = Taskmaster}
--- Adds a task to the loop.
---@param fn fun(Task) The main function to add, which receives the task as an argument
---@return Task task The created task
function Taskmaster:addTask(fn)
expect(1, fn, "function")
local task = setmetatable({coro = coroutine.create(fn), master = self, priority = 0}, Task_mt)
self.new[#self.new+1] = task
self.shouldSort = true
return task
end
--- Adds a task to the loop in builder style.
---@param fn fun(Task) The main function to add
---@return Taskmaster self
function Taskmaster:task(fn) self:addTask(fn) return self end
--- Adds a function to the loop. This is just like a task, but allows extra arguments.
---@param fn function The main function to add, which receives the arguments passed
---@param ... any Any arguments to pass to the function
---@return Task task The created task
function Taskmaster:addFunction(fn, ...)
expect(1, fn, "function")
local args = table.pack(...)
local task = setmetatable({coro = coroutine.create(function() return fn(table.unpack(args, 1, args.n)) end), master = self, priority = 0}, Task_mt)
self.new[#self.new+1] = task
self.shouldSort = true
return task
end
--- Adds a function to the loop in builder style.
---@param fn function The main function to add
---@param ... any Any arguments to pass to the function
---@return Taskmaster self
function Taskmaster:func(fn, ...) self:addFunction(fn, ...) return self end
--- Adds an event listener to the loop. This is a special task that calls a function whenever an event is triggered.
---@param name string The name of the event to listen for
---@param fn fun(string, ...) The function to call for each event
---@return Task task The created task
function Taskmaster:addEventListener(name, fn)
expect(1, name, "string")
expect(2, fn, "function")
local task = setmetatable({coro = coroutine.create(function() while true do fn(os.pullEvent(name)) end end), master = self, priority = 0}, Task_mt)
self.new[#self.new+1] = task
self.shouldSort = true
return task
end
--- Adds an event listener to the loop in builder style. This is a special task that calls a function whenever an event is triggered.
---@param name string The name of the event to listen for
---@param fn fun(string, ...) The function to call for each event
---@return Taskmaster self
function Taskmaster:eventListener(name, fn) self:addEventListener(name, fn) return self end
--- Adds a task that triggers a function repeatedly after an interval. The function may modify or cancel the interval through a return value.
---@param timeout number The initial interval to run the function after
---@param fn fun():number|nil The function to call.
---If this returns a number, that number replaces the timeout.
---If this returns a number less than or equal to 0, the timer is canceled.
---If this returns nil, the timeout remains the same.
---@return Task task The created task
function Taskmaster:addTimer(timeout, fn)
expect(1, timeout, "number")
expect(2, fn, "function")
local task = setmetatable({coro = coroutine.create(function()
while true do
sleep(timeout)
timeout = fn() or timeout
if timeout <= 0 then return end
end
end), master = self, priority = 0}, Task_mt)
self.new[#self.new+1] = task
self.shouldSort = true
return task
end
--- Adds a task that triggers a function repeatedly after an interval in builder style. The function may modify or cancel the interval through a return value.
---@param timeout number The initial interval to run the function after
---@param fn fun():number|nil The function to call.
---If this returns a number, that number replaces the timeout.
---If this returns a number less than or equal to 0, the timer is canceled.
---If this returns nil, the timeout remains the same.
---@return Taskmaster self
function Taskmaster:timer(timeout, fn) self:addTimer(timeout, fn) return self end
--- Creates a new queue. A queue allows pushing items for other tasks to pop,
--- functioning similarly to the CC event queue but without a size limit.
---
--- A queue may have items of any type pushed to its tail, from inside a task or
--- outside the loop. Tasks may pop those items from the queue, and they will
--- wait until the queue has an item to return it (if the queue has an item
--- already, it returns immediately without waiting). Smart logic is in place to
--- minimize the number of events required to awaken waiting tasks.
---
--- Be aware there is a significant difference in behavior from the event queue
--- across multiple tasks: items in the queue are not duplicated across tasks,
--- so if multiple tasks are awaiting a new item, only one task will receive the
--- next item, and it will immediately be removed. The task which receives this
--- item is undefined. If multiple items are queued without yielding, they will
--- be distributed across tasks (again, which tasks and their order are
--- undefined). If you need a queue that distributes across awaiting tasks, use
--- a multi queue.
---
--- This queue is bound to the Taskmaster loop. Items may be pushed from any
--- context (provided any awakening events don't get lost elsewhere), but
--- popping may only be done by a task running under this loop.
---@return Queue queue The new queue
function Taskmaster:createQueue()
return setmetatable({loop = self, head = 1, tail = 1, waiting = setmetatable({}, {__mode = "k"})}, Queue_mt)
end
--- Creates a new multi queue. A multi queue is a combination of queues for each
--- task that subscribes, with pushed items being distributed to all tasks. It
--- functions similarly to a normal queue, but each task gets every item pushed.
---@return MultiQueue queue The new multi queue.
function Taskmaster:createMultiQueue()
return setmetatable({loop = self, queues = setmetatable({}, {__mode = "k"})}, MultiQueue_mt)
end
--- Sets a blacklist for events to send to all tasks. Tasks can override this with their own blacklist.
---@param list? string[] A list of events to not send to any task
function Taskmaster:setEventBlacklist(list)
if expect(1, list, "table", "nil") then
self.blacklist = {}
for _, v in ipairs(list) do self.blacklist[v] = true end
else self.blacklist = nil end
end
--- Sets a whitelist for events to send to all tasks. Tasks can override this with their own whitelist.
---@param list? string[] A list of events to send to all tasks (others are discarded)
function Taskmaster:setEventWhitelist(list)
if expect(1, list, "table", "nil") then
self.whitelist = {}
for _, v in ipairs(list) do self.whitelist[v] = true end
else self.whitelist = nil end
end
--- Sets a function that is used to transform events. This function takes a task
--- and event table, and may modify the event table to adjust the event for that task.
---@param fn fun(Task, table)|nil A function to use to transform events
function Taskmaster:setEventTransformer(fn)
expect(1, fn, "function", "nil")
self.transformer = fn
end
--- Sets a function to call before yielding. This can be used to reset state such
--- as terminal cursor position.
---@param fn? fun() The function to call
function Taskmaster:setPreYieldHook(fn)
expect(1, fn, "function", "nil")
self.preYieldHook = fn
end
--- Sets the maximum number of tasks that can run concurrently.
---@param num? number The maximum number of tasks to run (default unlimited)
function Taskmaster:setMaxConcurrent(num)
expect(1, num, "number", "nil")
self.maxConcurrent = num
end
--- Runs the main loop, processing events and running each task.
---@param count? number The number of tasks that can exit before stopping the loop
function Taskmaster:run(count)
count = expect(1, count, "number", "nil") or math.huge
self.running = true
while self.running and (#self.tasks + #self.new) > 0 and count > 0 do
self.dead = {}
if not (self.maxConcurrent and #self.tasks >= self.maxConcurrent) then
local nextnew = {}
for i, task in ipairs(self.new) do
if self.maxConcurrent and #self.tasks >= self.maxConcurrent then
nextnew[#nextnew+1] = task
else
self.currentTask = task
local old = term.current()
local ok, filter = coroutine.resume(task.coro, task)
task.window = term.redirect(old)
if not ok then
self.currentTask = nil
self.running = false
self.new = {table.unpack(self.new, i + 1)}
return error(filter, 0)
end
task.filter = filter
if coroutine.status(task.coro) == "dead" then count = count - 1
else self.tasks[#self.tasks+1], self.shouldSort = task, true end
end
if not self.running or count <= 0 then break end
end
self.new = nextnew
end
if self.shouldSort then table.sort(self.tasks, function(a, b) return a.priority > b.priority end) self.shouldSort = false end
if self.running and #self.tasks > 0 and count > 0 then
if self.preYieldHook then self.preYieldHook() end
local _ev = table.pack(os.pullEventRaw())
for i, task in ipairs(self.tasks) do
local ev = _ev
if self.transformer then
ev = table.pack(table.unpack(_ev, 1, _ev.n))
self.transformer(task, ev)
end
local wl, bl = task.whitelist or self.whitelist, task.blacklist or self.blacklist
if not task.paused and
(task.filter == nil or task.filter == ev[1] or ev[1] == "terminate") and
(not bl or not bl[ev[1]]) and
(not wl or wl[ev[1]]) then
self.currentTask = task
local old = term.redirect(task.window)
local ok, filter = coroutine.resume(task.coro, table.unpack(ev, 1, ev.n))
task.window = term.redirect(old)
if not ok then
if task.errh then
task.errh(filter, task)
else
self.currentTask = nil
self.running = false
table.remove(self.tasks, i)
return error(filter, 0)
end
end
task.filter = filter
if coroutine.status(task.coro) == "dead" then self.dead[#self.dead+1] = task end
if not self.running or #self.dead >= count then break end
end
end
end
self.currentTask = nil
for _, task in ipairs(self.dead) do
for i, v in ipairs(self.tasks) do
if v == task then
table.remove(self.tasks, i)
count = count - 1
break
end
end
end
end
self.running = false
end
--- Runs all tasks until a single task exits.
function Taskmaster:waitForAny() return self:run(1) end
--- Runs all tasks until all tasks exit.
function Taskmaster:waitForAll() return self:run() end
--- Stops the main loop if it is running. This will yield if called from a running task.
function Taskmaster:stop()
self.running = false
if self.currentTask then coroutine.yield() end
end
Taskmaster_mt.__call = Taskmaster.run
local function fetch(loop, url, ...)
local ok, err = http.request(url, ...)
if not ok then return Promise:_reject(loop, err) end
return loop.Promise.new(function(resolve, reject)
while true do
local event, p1, p2, p3 = os.pullEvent()
if event == "http_success" and p1 == url then
p2.text = function()
return loop.Promise.new(function(_resolve, _reject)
local data = p2.readAll()
p2.close()
_resolve(data)
end)
end
p2.json = function()
return loop.Promise.new(function(_resolve, _reject)
local data = p2.readAll()
p2.close()
local d = textutils.unserializeJSON(data)
if d ~= nil then _resolve(d)
else _reject("Failed to parse JSON") end
end)
end
p2.table = function()
return loop.Promise.new(function(_resolve, _reject)
local data = p2.readAll()
p2.close()
local d = textutils.unserialize(data)
if d ~= nil then _resolve(d)
else _reject("Failed to parse Lua table") end
end)
end
return resolve(p2)
elseif event == "http_failure" and p1 == url then
if p3 then p3.close() end
return reject(p2)
end
end
end)
end
--- Creates a new Taskmaster run loop.
---@param ... fun() Any tasks to add to the loop
---@return Taskmaster loop The new Taskmaster
return function(...)
local loop = setmetatable({tasks = {}, dead = {}, new = {}}, Taskmaster_mt)
for i, v in ipairs{...} do
expect(i, v, "function")
loop:addTask(v)
end
loop.Promise = {
new = function(fn) return Promise:new(loop, fn) end,
all = function(list) return Promise:all(loop, list) end,
any = function(list) return Promise:any(loop, list) end,
race = function(list) return Promise:race(loop, list) end,
resolve = function(val) return Promise:_resolve(loop, val) end,
reject = function(err) return Promise:_reject(loop, err) end,
fetch = function(...) return fetch(loop, ...) end
}
setmetatable(loop.Promise, {__call = function(self, ...) return Promise:new(loop, ...) end})
return loop
end

384
prog2/ticTackToe.lua Normal file
View File

@@ -0,0 +1,384 @@
os.pullEvent=os.pullEventRaw
if fs.exists("/disk/terminate") then
error("Service mode active",2)
end
--tic
--[[
TIC-TAC-TOE
by Evan Hahn (http://www.evanhahn.com/)
This is a program that allows you to play tic-tac-toe against the
computer.
You may change the configuration (below) to make the board more than 3x3,
or play with "white" and "black" instead of "x" and "o", and change how
the board is displayed.
How it works:
The board is represented by a 2D table of spaces. They are filled with
nil to start. When you play, you put an "x" or an "o" into the table. The
board is used to keep track of piece locations and to display them. It
does not calculate wins.
The board also has regions. A region is a place where a player may win
(horizontal, vertical, or diagonal). It holds pointers to the board table.
Player 1 is represented by +, and Player 2 by -. Each piece in the region
increments or decrements the checking of the region. Basically, two X's
returns as 2. Two O's returns as -2. 3 or -3 is a winning region.
Some notes:
- There are other ways to program this, but I did not elect to use them.
One alternate way: Generate a table that holds string representations
of all the winning boards. Check for wins against that table instead.
- I am unfamiliar with accepted style and best practices of Lua, and
my code may reflect that.
--]]
----------------------------------------------
-- Configuration (change this if you wish!) --
----------------------------------------------
-- Are they playable by human or computer-controlled?
PLAYER_1_HUMAN = true
PLAYER_2_HUMAN = false
-- Board size
BOARD_RANK = 3 -- The board will be this in both dimensions.
-- Display stuff
PLAYER_1 = "x" -- Player 1 is represented by this. Player 1 goes first.
PLAYER_2 = "o" -- Player 2 is represented by this.
EMPTY_SPACE = " " -- An empty space is displayed like this.
DISPLAY_HORIZONTAL_SEPARATOR = "-" -- Horizontal lines look like this.
DISPLAY_VERTICAL_SEPARATOR = " | " -- Vertical lines look like this
--[[ ###################################################################
#### Don't mess with things below here unless you are brave ####
################################################################### --]]
------------------------
-- More configuration --
------------------------
MAX_BOARD_RANK = 100 -- Won't run above this number. Prevents crashes.
-------------------------------------------------------
-- Don't run if the board is larger than the maximum --
-------------------------------------------------------
if BOARD_RANK > MAX_BOARD_RANK then os.exit(0) end
-----------------------------
-- Create board (2D table) --
-----------------------------
space = {}
for i = 0, (BOARD_RANK - 1) do
space[i] = {}
for j = 0, (BOARD_RANK - 1) do
space[i][j] = nil -- start each space with nil
end
end
---------------------
-- Board functions --
---------------------
-- get the piece at a given spot
function getPiece(x, y)
return space[x][y]
end
-- get the piece at a given spot; if nil, return " "
-- this is useful for output.
function getPieceNoNil(x, y)
if getPiece(x, y) ~= nil then
return getPiece(x, y)
else
return EMPTY_SPACE
end
end
-- is that space empty?
function isEmpty(x, y)
if getPiece(x, y) == nil then
return true
else
return false
end
end
-- place a piece there, but make sure nothing is there already.
-- if you can't play there, return false.
function placePiece(x, y, piece)
if isEmpty(x, y) == true then
space[x][y] = piece
return true
else
return false
end
end
-- is the game over?
function isGameOver()
if checkWin() == false then -- if there is no win...
for i = 0, (BOARD_RANK - 1) do -- is the board empty?
for j = 0, (BOARD_RANK - 1) do
if isEmpty(i, j) == true then return false end
end
end
return true
else -- there is a win; the game is over
return true
end
end
-- create a string made up of a certain number of smaller strings
-- this is useful for the display.
function repeatString(to_repeat, amount)
if amount <= 0 then return "" end
local to_return = ""
for i = 1, amount do
to_return = to_return .. to_repeat
end
return to_return
end
-- display the board.
-- this uses the configuration file pretty much entirely.
function displayBoard()
-- find the widest player
local widest_piece = math.max(string.len(PLAYER_1), string.len(PLAYER_2), string.len(EMPTY_SPACE))
-- display board, top to bottom
io.write("\n") -- make sure it starts on a new line
for i = (BOARD_RANK - 1), 0, -1 do
local row = "" -- start with an empty row
for j = 0, (BOARD_RANK - 1) do -- generate that row
local piece = getPieceNoNil(j, i)
row = row .. piece
row = row .. repeatString(" ", widest_piece - string.len(piece))
if j ~= (BOARD_RANK - 1) then
row = row .. DISPLAY_VERTICAL_SEPARATOR
end
end
io.write(row) -- output row
if i ~= 0 then -- output horizontal line as long as the row
io.write("\n")
local repeats = math.ceil(string.len(row) / string.len(DISPLAY_HORIZONTAL_SEPARATOR))
io.write(repeatString(DISPLAY_HORIZONTAL_SEPARATOR, repeats))
io.write("\n")
end
end
-- finish off with a line break
io.write("\n")
end
-------------------------------------------------
-- Create regions (I admit this is a bit ugly) --
-------------------------------------------------
-- declare region and a number to increment
region = {}
region_number = 0
-- vertical
for i = 0, (BOARD_RANK - 1) do
region[region_number] = {}
for j = 0, (BOARD_RANK - 1) do
region[region_number][j] = {}
region[region_number][j]["x"] = i
region[region_number][j]["y"] = j
end
region_number = region_number + 1
end
-- horizontal
for i = 0, (BOARD_RANK - 1) do
region[region_number] = {}
for j = 0, (BOARD_RANK - 1) do
region[region_number][j] = {}
region[region_number][j]["x"] = j
region[region_number][j]["y"] = i
end
region_number = region_number + 1
end
-- diagonal, bottom-left to top-right
region[region_number] = {}
for i = 0, (BOARD_RANK - 1) do
region[region_number][i] = {}
region[region_number][i]["x"] = i
region[region_number][i]["y"] = i
end
region_number = region_number + 1
-- diagonal, top-left to bottom-right
region[region_number] = {}
for i = (BOARD_RANK - 1), 0, -1 do
region[region_number][i] = {}
region[region_number][i]["x"] = BOARD_RANK - i - 1
region[region_number][i]["y"] = i
end
region_number = region_number + 1
----------------------
-- Region functions --
----------------------
-- get a region
function getRegion(number)
return region[number]
end
-- check for a win in a particular region.
-- returns a number representation of the region. occurrences of player 1
-- add 1, occurrences of player 2 subtract 1. so if there are two X pieces,
-- it will return 2. one O will return -1.
function checkWinInRegion(number)
local to_return = 0
for i, v in pairs(getRegion(number)) do
local piece = getPiece(v["x"], v["y"])
if piece == PLAYER_1 then to_return = to_return + 1 end
if piece == PLAYER_2 then to_return = to_return - 1 end
end
return to_return
end
-- check for a win in every region.
-- returns false if no winner.
-- returns the winner if there is one.
function checkWin()
for i in pairs(region) do
local win = checkWinInRegion(i)
if math.abs(win) == BOARD_RANK then
if win == math.abs(win) then
return PLAYER_1
else
return PLAYER_2
end
end
end
return false
end
------------------
-- UI Functions --
------------------
-- human play
function humanPlay(piece)
io.write(piece .. ", here's the board:\n")
displayBoard()
local placed = false
while placed == false do -- loop until they play correctly
io.write("\nWhere would you like to play your " .. piece .. "?\n")
io.write("Give the X-coordinate (starting with 0). ")
local x = tonumber(io.read())
io.write("Now give the Y-coordinate (starting with 0). ")
local y = tonumber(io.read())
placed = placePiece(x, y, piece)
if placed == false then
io.write("I'm afraid you can't play there!")
end
end
displayBoard()
io.write("\n")
end
-- AI play
function AIPlay(piece)
-- am I negative or positive?
local me = 0
if piece == PLAYER_1 then me = 1 end
if piece == PLAYER_2 then me = -1 end
-- look for a region in which I can win
for i in pairs(region) do
local win = checkWinInRegion(i)
if win == ((BOARD_RANK - 1) * me) then
for j, v in pairs(getRegion(i)) do
if isEmpty(v["x"], v["y"]) == true then
placePiece(v["x"], v["y"], piece)
return
end
end
end
end
-- look for a region in which I can block
for i in pairs(region) do
local win = checkWinInRegion(i)
if win == ((BOARD_RANK - 1) * (me * -1)) then
for j, v in pairs(getRegion(i)) do
if isEmpty(v["x"], v["y"]) == true then
placePiece(v["x"], v["y"], piece)
return
end
end
end
end
-- play first empty space, if no better option
for i = 0, (BOARD_RANK - 1) do
for j = 0, (BOARD_RANK - 1) do
if placePiece(i, j, piece) ~= false then return end
end
end
end
----------
-- Main --
----------
-- welcome!
io.write("Welcome to Tic-Tac-Toe!\n\n")
-- play the game until someone wins
while true do
-- break if the game is won
if isGameOver() == true then break end
-- player 1
if PLAYER_1_HUMAN == true then humanPlay(PLAYER_1)
else AIPlay(PLAYER_1) end
sleep(1)
shell.run("clear all")
-- break if the game is won
if isGameOver() == true then break end
-- player 2
if PLAYER_2_HUMAN == true then humanPlay(PLAYER_2)
else AIPlay(PLAYER_2) end
end
-- show the final board
io.write("The final board:\n")
displayBoard()
io.write("\n")
-- write who won, or if there is a tie
win = checkWin()
if win == false then
io.write("Tie game!\n")
else
io.write(win)
io.write(" wins!\n")
end
sleep(5)
shell.run("clear all")
shell.run("startup")

114
wirelessCode/Slot.lua Normal file
View File

@@ -0,0 +1,114 @@
local wireless = require("wireless")
os.pullEvent= function(...)
while true do
local t = table.pack(os.pullEventRaw(...))
if t[1] ~= "terminate" then
return table.unpack(t,1,t.n)
end
end
end
local function interactWithCard(userUUID, mode, money)
if mode == "updateBalance" then
wireless.broadcast({
uuid = userUUID,
amount = money,
type = "set"
}, "machineBalanceModifier")
end
if mode == "getBalance" then
local _, _, cardUUID = os.pullEvent("nfc_data")
wireless.broadcast({
card = cardUUID
}, "getAccountData")
while true do
local id, message = wireless.receive("server_response", 10)
if not id then
print("the server is down")
print("please ping @minecartchris")
sleep(30)
--shell.run("reboot")
end
if not message then
print("WTF!? I got a rednet message with no data!?")
print("Rebooting...")
sleep(5)
end
if message.type == "account_data" and message.cardId == cardUUID then
local money = message.balance
local playerUUID = message.uuid
local username = message.username
return money, playerUUID, username
end
end
end
end
sleep(0.25)
nfc = peripheral.wrap("bottom")
if fs.exists("/disk/terminate") then
error("Service mode active",2)
end
modem = peripheral.wrap("back")
shell.run("clear all")
--while not fs.exists("/disk2/money.lua") do
--sleep(0.75)
--print("You do not have a card inserted")
--sleep(2)
--shell.run("clear all")
--end
--print("Please do not remove your card from the drive during games")
local money = " "
local winner = false
local randnum = 0
local bet = 0
--local money2 = fs.open("/disk2/money.lua", "r")
print("Welcome to the Slot Machine!")
print("Please swipe your card to begin")
--local _, _, userUUID = os.pullEvent("nfc_data")
money, playerUUID, username = interactWithCard(nil, "getBalance", nil)
--money2.close()
print("Welcome "..tostring(username))
print("$",money)
money = tonumber(money)
print("what is your bet?")
bet = tonumber(io.read())
print("what is your guess 1 to 15?")
userGess = tonumber(io.read())
if not bet or bet > money or bet < 0 then
print("You do not have enough funds or did not enter a bet.")
sleep(3)
shell.run("reboot")
end
randnum = tonumber(math.random(0, 14) + 1)
if userGess == randnum then
winner = true
end
if not winner then
print("you lost ;(")
print("The correct number was", randnum)
money = money - bet
print("you have $",money, "left over")
interactWithCard(playerUUID, "updateBalance", money)
end
if winner then
bet = bet * 2
money = bet + money
print("You win!!!!!")
print("You now have $", money)
interactWithCard(playerUUID, "updateBalance", money)
end
sleep(2)
os.reboot()

View File

@@ -0,0 +1 @@
https://github.com/migeyel/ccryptolib/tree/main/ccryptolib

118
wirelessCode/wireless.lua Normal file
View File

@@ -0,0 +1,118 @@
local key = ""
local wirelessChannel = 44385
local wirelessModem = assert(peripheral.wrap("top"))
wirelessModem.open(wirelessChannel)
local random = require("ccryptolib.random")
local aead = require("ccryptolib.aead")
local seed = ""
-- this isnt exactly secure, but its fine, probably..
for i=1,64 do
seed = seed .. string.char(math.random(0, 255))
end
random.init(seed)
local function encrypt(message)
local nonce = random.random(12)
local ciphertext, tag = aead.encrypt(key, nonce, message, "")
return nonce..tag..ciphertext
end
local function decrypt(message)
local ciphertextLength = #message-12-16
if ciphertextLength < 0 then
printError("message too short, this may be caused by other traffic on the same port")
return
end
if ciphertextLength >= 32768 then
printError("message too large, this may be caused by other traffic on the same port")
return
end
local nonce, tag, endPos = string.unpack("c12c16", message)
local ciphertext = message:sub(endPos)
local decryptedMessage = aead.decrypt(key, nonce, tag, ciphertext, "") -- this is nil if auth failed
if not decryptedMessage then
printError("message auth invalid")
return
end
return decryptedMessage
end
local function sendWireless(tbl)
local str = textutils.serialize(tbl)
if not str then
printError("failed to serialize message")
return
end
local enc = encrypt(str)
if not enc then
printError("failed to encrypt serialized message")
return
end
wirelessModem.transmit(wirelessChannel, wirelessChannel, enc)
end
local function recvWireless()
while true do
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
if side == peripheral.getName(wirelessModem) and channel == wirelessChannel then
local dec = decrypt(message)
if dec then
local unser = textutils.unserialize(dec)
if unser then
return unser
else
printError("failed to unserialize")
end
end
end
end
end
return {
broadcast = function(data, protocol)
local message_wrapper = {
nMessageID = math.random(1, 2147483647), -- we dont store messageid here because we shouldnt get our messages back
nRecipient = rednet.CHANNEL_BROADCAST,
nSender = os.getComputerID(),
message = data,
sProtocol = protocol,
}
sendWireless(message_wrapper)
end,
receive = function(protocol, timeout) -- computer ids not implemented
local ret = {}
parallel.waitForAny(function()
while true do
local msg = recvWireless()
if type(msg) == "table" then
ret = {msg.nMessageID, msg.message, msg.sProtocol}
return
end
end
end, function() -- this sucks as well
while not timeout do sleep(1) end
sleep(timeout)
ret = {}
end)
return table.unpack(ret)
end
}