Skip to content

Instantly share code, notes, and snippets.

@MineRobber9000
Last active August 11, 2023 02:09
Show Gist options
  • Save MineRobber9000/7d735c2cd6620760670b9658760b4790 to your computer and use it in GitHub Desktop.
Save MineRobber9000/7d735c2cd6620760670b9658760b4790 to your computer and use it in GitHub Desktop.
Dartmouth BASIC interpreter
local functions = {}
for v in ("ABS ATN COS EXP INT LOG RND SIN SQR TAN "):gmatch("(.-) ") do
functions[v]=true
end
for c in ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"):gmatch("(.)") do
functions["FN"..c]=true
end
local statements = {}
for v in ("LET PRINT END READ DATA GOTO IF FOR NEXT GOSUB RETURN DEF DIM REM STOP INPUT "):gmatch("(.-) ") do
statements[v]=true
end
local keywords={["THEN"]=true,["TO"]=true,["STEP"]=true}
local function startsWithLUTValue(s,lut)
for k,v in pairs(lut) do
if s:find(k,1,true)==1 then return true, k end
end
return false
end
local function symbol(type,...)
return {type=type,...}
end
local function lexer(s)
if s:sub(-1,-1)~="\n" then s=s.."\n" end
s=s:upper()
local ret = {}
for line in s:gmatch("(.-)\n") do
local flag=false
local n=""
line:gsub("(.)",function(c)
if c:find("%s") and not flag then
-- skip
elseif c=='"' then
n=n..c
flag=not flag
else
n=n..c
end
end)
line=n
local ret2={}
while #line>0 do
-- number
if line:find("%d?%.?%d+")==1 then
local num = line:sub(line:find("%d?%.?%d+"))
line=line:sub(#num+1)
if line:find("E%-?%d+")==1 then
local e = line:sub(line:find("E%-?%d+"))
line=line:sub(#e+1)
num=num..e
end
ret2[#ret2+1]=symbol("number",tonumber(num))
elseif startsWithLUTValue(line,functions) then
local _, func = startsWithLUTValue(line,functions)
ret2[#ret2+1]=symbol("function",func)
line=line:sub(#func+1)
elseif startsWithLUTValue(line,statements) then
local _, stmt = startsWithLUTValue(line,statements)
ret2[#ret2+1]=symbol("statement",stmt)
line=line:sub(#stmt+1)
elseif startsWithLUTValue(line,keywords) then
local _,keyword = startsWithLUTValue(line,keywords)
ret2[#ret2+1]=symbol("keyword",keyword)
line=line:sub(#keyword+1)
elseif line:find("[A-Z]")==1 then
local c
c, line = line:sub(1,1), line:sub(2)
if line:find("%d")==1 then
local n
n, line = line:sub(1,1), line:sub(2)
c=c..n
end
ret2[#ret2+1]=symbol("var",c)
elseif line:find('".-"')==1 then
local s = line:sub(line:find('".-"'))
line=line:sub(#s+1)
ret2[#ret2+1]=symbol("label",s:sub(2,-2))
elseif line:find("<>")==1 or line:find(">=")==1 or line:find("<=")==1 then
local op
op, line = line:sub(1,2), line:sub(3)
ret2[#ret2+1] = symbol("rel",op)
else
ret2[#ret2+1]=symbol(line:sub(1,1))
line=line:sub(2)
end
end
ret[#ret+1]=ret2
end
return ret
end
local function queue(terms)
local ret = {}
for i=#terms,1,-1 do ret[#ret+1]=terms[i] end
ret.peek=function() return ret[#ret] end
ret.pop=function(cond)
cond=cond or (function() return true end)
if type(cond)=="string" then
local c1=cond
cond=function(tok) return tok and tok.type==c1 end
end
if cond(ret[#ret]) then
return table.remove(ret)
end
end
return ret
end
local nop = function() end
local function linenumber(q,em)
local num = assert(q.pop("number"),em or "missing line number")[1]
return math.floor(num)
end
local function number(q,em)
local sgn=1
if q.pop("-") then sgn=-1 end
return sgn*(assert(q.pop("number"),em or "expected number")[1])
end
local expression -- so variable can call it
local function variable(q,var)
local v = var or assert(q.pop("var"),"expected variable name")[1]
if q.pop("(") then
local i = expression(q)
v=v.."["..i.."]"
if q.pop(",") then
local i2 = expression(q)
v=v.."["..i2.."]"
end
assert(q.pop(")"),"expected ) to end subscript")
end
return v
end
local function func(q,v)
local v = v or assert(q.pop("function"),"expected function name")[1]
assert(q.pop('('),"expected ( to start function argument")
local arg = expression(q)
assert(q.pop(')'),"expected ) to end function argument")
return ("e.%s(e,%s)"):format(v,arg)
end
local function is_valid_for_expression(lvl)
return function(tok)
if not tok then return false end
local r=false
("+-*/%^("..(lvl>0 and ")" or "")):gsub("(.)",function(c)
if tok.type==c then r=true end
end)
if r then return true end
if tok.type=="number" then return true end
if tok.type=="function" then return true end
if tok.type=="var" then return true end
return false
end
end
function expression(q,em)
local exp = ""
local arrays = {}
local lvl = 0
local tok = q.pop(is_valid_for_expression(lvl))
while tok do
if tok.type=="number" then
exp=exp..tok[1]
elseif tok.type=="function" then
exp=exp..func(q,tok[1])
elseif tok.type=="var" then
local var = variable(q,tok[1])
exp=exp.."e."..var
if var:find("[",1,true)~=nil then
arrays[#arrays+1]={var:sub(1,var:find("[",1,true)-1),select(2,var:gsub("%[",""))}
end
elseif tok.type=="(" then
exp=exp.."("
lvl=lvl+1
elseif tok.type==")" then
exp=exp..")"
lvl=lvl-1
else
exp=exp..tok.type
end
tok = q.pop(is_valid_for_expression(lvl))
end
assert(exp~="",(em or "expected expression"))
return exp, arrays
end
local function is_keyword(kw)
return function(tok)
return tok and tok.type=="keyword" and tok[1]==kw
end
end
local stop=function(e) e.stop=true e.no_end=false end
local _return=function(e)
if not e._return then
error("RETURN without GOSUB")
end
e.jump(e._return)
e._return=nil
end
local function parser(lines,prog)
prog = prog or {data={},userfuncs={},array_dims={}}
for i=1,#lines do
local q = queue(lines[i])
local lineno = linenumber(q,"missing line number at index "..i)
local stmt = assert(q.pop("statement"),"missing statement at index "..i)[1]
if stmt=="REM" then
prog[lineno]=nop
elseif stmt=="LET" then
local var = variable(q)
assert(q.pop('='),"expected equals sign")
local exp, arrays = expression(q,"expected expression for LET")
assert(#q==0,"invalid LET statement")
prog[lineno]=load("return function(e) e."..var.."=("..exp..")end")()
for i=1,#arrays do
if not prog.array_dims[arrays[i][1]] then
if arrays[i][2]==1 then
prog.array_dims[arrays[i][1]]={10}
else
prog.array_dims[arrays[i][1]]={10,10}
end
end
end
elseif stmt=="PRINT" then
local args={}
while #q>0 do
if q.peek().type=="label" then
args[#args+1]='"'..q.pop()[1]..'"'
elseif q.peek().type==";" then
q.pop() --nop
elseif q.peek().type=="," then
args[#args+1]="true"
q.pop()
else
args[#args+1]=expression(q,"expected expression for PRINT")
end
end
prog[lineno]=load("return function(e) e.print("..table.concat(args,", ")..") end")()
elseif stmt=="END" or stmt=="STOP" then
prog[lineno]=stop
elseif stmt=="READ" then
local parts = {"if #e.data then e."..variable(q).."=e.data.pop() end"}
while q.pop(",") do
parts[#parts]="if #e.data then e."..variable(q).."=e.data.pop() end"
end
assert(#q==0,"invalid READ statement")
local p=table.concat(parts," ")
prog[lineno]=load("return function(e) "..p.." end")()
elseif stmt=="DATA" then
local nums = {}
nums[1]=number(q,"expected number for DATA")
while q.pop(",") do
nums[#nums+1]=number(q,"expected number for DATA")
end
assert(#q==0,"invalid DATA statement")
prog.data[lineno]=nums
elseif stmt=="GOTO" then
local dest=linenumber(q,"missing line number for GOTO")
assert(#q==0,"invalid GOTO statement")
prog[lineno]=load("return function(e) e.jump("..dest..") end")()
elseif stmt=="IF" then
local exp = expression(q,"expected expression for IF1")
local rel
if q.peek() and (q.peek().type=="=" or q.peek().type=="<" or q.peek().type==">") then rel=q.pop().type end
rel = rel or assert(q.pop("rel"),"expected relational operator")[1]
local exp2 = expression(q,"expected expression for IF2")
assert(q.pop(is_keyword("THEN")),"expected THEN")
local dest=linenumber(q,"missing line number for IF")
prog[lineno]=load(("return function(e) if (%s)%s(%s) then e.jump(%d) end end"):format(exp,(rel=="<>" and "~=" or (rel=="=" and "==" or rel)),exp2,dest))()
elseif stmt=="FOR" then
local var = variable(q)
assert(var:find("[",1,true)==nil,"cannot use subscripted variable for FOR loop")
assert(q.pop("="),"expected equals sign for FOR")
local expStart = expression(q,"expected expression for FOR")
assert(q.pop(is_keyword("TO")),"expected TO")
local expEnd = expression(q,"expected expression for FOR")
local expStep = 1
if is_keyword("STEP")(q.peek()) then
expStep=expression(q,"expected expression for FOR")
end
prog[lineno]=load(("return function(e) if not e.fors.%s then e.fors.%s={%d,%s,%s,%s} e.%s=%s end end"):format(var,var,lineno,expStart,expEnd,expStep,var,expStart))()
elseif stmt=="NEXT" then
local var = variable(q)
assert(#q==0,"invalid NEXT statement")
prog[lineno]=load(("return function(e) e.fors.%s[2]=e.fors.%s[2]+e.fors.%s[4] if e.fors.%s[2]<=e.fors.%s[3] then e.%s=e.fors.%s[2] e.jump(e.fors.%s[1]) end end"):format(var,var,var,var,var,var,var,var))()
elseif stmt=="GOSUB" then
local dest=linenumber(q,"missing line number for GOSUB")
assert(#q==0,"invalid GOSUB statement")
prog[lineno]=load(("return function(e) e._return=%d e.jump(%d) end"):format(lineno+1,dest))()
elseif stmt=="RETURN" then
assert(#q==0,"invalid RETURN statement")
prog[lineno]=_return
elseif stmt=="DEF" then
local func = assert(q.pop("function"),"expected function name for DEF")[1]
assert(func:sub(1,2)=="FN","cannot redefine standard function "..func)
assert(q.pop("("),"expected ( to start function argument")
local arg = assert(q.pop("var"),"expected variable for function argument")
assert(q.pop(")"),"expected ) to end function argument")
assert(q.pop("="),"expected = for DEF")
local exp = expression(q,"expected expression for DEF")
assert(#q==0,"invalid DEF statement")
prog.userfuncs[func]=load(("return function(e,var) local tmp = e.%s e.%s=var local ret=(%s) e.%s=tmp return ret end"):format(arg,arg,exp,arg))()
elseif stmt=="DIM" then
local var1 = assert(q.pop("var"),"expected variable name for DIM")[1]
assert(q.pop("("),"expected ( for DIM")
local dim1 = number(q,"expected number for DIM")
local dim2 = nil
if q.pop(",") then dim2=number(q,"expected number for DIM") end
assert(q.pop(")"),"expected ) for DIM")
prog.array_dims[var1]={dim1,dim2}
while q.pop(",") do
local var1 = assert(q.pop("var"),"expected variable name for DIM")[1]
assert(q.pop("("),"expected ( for DIM")
local dim1 = number(q,"expected number for DIM")
local dim2 = nil
if q.pop(",") then dim2=number(q,"expected number for DIM") end
assert(q.pop(")"),"expected ) for DIM")
prog.array_dims[var1]={dim1,dim2}
end
elseif stmt=="INPUT" then
local var = "e."..variable(q)
assert(#q==0,"invalid INPUT statement")
prog[lineno]=load("return function(e) "..var.."=e.input() end")()
else
error("unsupported statement "..stmt)
end
end
return prog
end
local function getLineNumbers(prog)
local linenos = {}
for k,v in pairs(prog) do
if type(k)=="number" then
linenos[#linenos+1]=k
end
end
table.sort(linenos)
return linenos
end
local function _print(size)
local zone_width = math.floor(size/5)
-- cap to 75 characters wide as in the original
if zone_width>15 then zone_width=15 end
local size = zone_width*5
return function(...)
-- TODO: implement column based printing like I'm supposed to
local parts = table.pack(...)
local lines={""}
for i=1,#parts do
if parts[i]==true then
-- Dartmouth BASIC used 15-character zones for a 75-char wide screen
-- Ergo, our zones are whatever size it takes to get 5 zones on our screen.
-- Capped at 15 character zones for a screen width of 75
local target = (math.floor(#lines[#lines]/10)+1)*10
lines[#lines]=lines[#lines]..(" "):rep(target-#lines[#lines])
else
local part = tostring(parts[i])
lines[#lines] = lines[#lines]..part
if i~=#parts and #lines[#lines]<size then lines[#lines] = lines[#lines].." " end
end
if #lines[#lines]==size then
lines[#lines+1]=""
elseif #lines[#lines]>size then
local line=lines[#lines]:sub(1,size)
local leftover=lines[#lines]:sub(size+1)
lines[#lines]=line
lines[#lines+1]=leftover
end
end
for i=1,#lines do
textutils.slowPrint(lines[i],10)
sleep(0.1)
end
end
end
local function _input()
write("? ")
local input=read()
while not tonumber(input) do
print("ENTER NUMBER")
write("? ")
input=read()
end
return tonumber(input)
end
local _wrap=function(f) return function(e,arg) return f(arg) end end
local standardFunctions = {
ABS=_wrap(math.abs),
ATN=_wrap(math.atan),
COS=_wrap(math.cos),
EXP=_wrap(math.exp),
INT=function(e,n) if n<0 then return math.ceil(n) end return math.floor(n) end,
LOG=_wrap(math.log),
SIN=_wrap(math.sin),
SQR=function(e,n) return n^2 end,
TAN=_wrap(math.tan)
}
local function addRand(env)
local __uint32limit = 0xFFFFFFFF
local function __mulberry32(a) -- mulberry32 used to seed the RNG state
a=bit32.band((a+0x6D2B79F5),__uint32limit)
local t = bit32.band((bit32.bxor(a,bit32.rshift(a,15))*bit32.bor(1,a)),__uint32limit)
t = t + bit32.band((bit32.bxor((bit32.bxor(t,bit32.rshift(t,7))*bit32.bor(61,t)),t)),__uint32limit)
return a, t
end
local s = {}
local a = 19640501 -- May 1st, 1964, beginning of DTSS and BASIC
a, s[0] = __mulberry32(a)
a, s[1] = __mulberry32(a)
a, s[2] = __mulberry32(a)
a, s[3] = __mulberry32(a)
env.RND = function()
local result = bit32.band((s[0]+s[3]),__uint32limit)
local t = bit32.band(bit32.lshift(s[1],9),__uint32limit)
s[2]=bit32.bxor(s[2],s[0])
s[3]=bit32.bxor(s[3],s[1])
s[1]=bit32.bxor(s[1],s[2])
s[0]=bit32.bxor(s[0],s[3])
s[2]=bit32.bxor(s[2],t)
s[3]=bit32.lrotate(s[3],11)
return result/__uint32limit
end
end
local function run(prog)
local linenos = getLineNumbers(prog)
local indices = {}
for k,v in pairs(linenos) do indices[v]=k end
local env = {}
env.print = _print(term.getSize())
env.input = _input
env.stop=false
env.no_end=true
env.fors={}
local pc=linenos[1]
env.jump=function(lineno)
pc=lineno
end
local data = {}
local data_linenos = getLineNumbers(prog.data)
for i=1,#data_linenos do
local d = prog.data[data_linenos[i]]
for j=1,#d do
table.insert(data,d[j])
end
end
env.data = queue(data)
for k,v in pairs(standardFunctions) do env[k]=v end
addRand(env)
for k,v in pairs(prog.userfuncs) do env[k]=v end
for k,v in pairs(prog.array_dims) do
if #v==1 then
env[k]={}
else
env[k]=setmetatable({},{__index=function(t,k) t[k]={} return t[k] end})
end
end
while (not env.stop) do
while not prog[pc] do pc=pc+1 end
local f = prog[pc]
pc=pc+1 -- this can get overwritten so do it before we call f
f(env)
if pc>linenos[#linenos] then env.stop=true end
end
if env.no_end then printError("missing END statement") end
end
return {
lexer=lexer,
parser=parser,
run=run
}
0 REM * FTBALL *
10 PRINT "THIS IS DARTMOUTH CHAMPIONSHIP FOOTBALL."
20 PRINT "YOU WILL QUARTERBACK DARTMOUTH. CALL PLAYS AS FOLLOWS:"
30 PRINT "1 = SIMPLE RUN; 2 = TRICKY RUN; 3 = SHORT PASS;"
40 PRINT "4 = LONG PASS; 5 = PUNT; 6 = QUICK KICK;' 7 = PLACE KICK."
45 PRINT
50 LET T = 0
60 LET S(0) = 0
70 LET S(2) = 0
100 PRINT "TOSS OF COIN. (TYPE A NO. FROM 1 TO 300)";
120 INPUT Z1
140 FOR I = 1 TO Z1
160 LET X = RND(X)
180 NEXT I
190 IF RND(Z) > 1/2 THEN 195
191 PRINT "PRINCETON WON THE TOSS"
193 GOTO 2180
195 PRINT "DARTMOUTH WON THE TOSS"
200 PRINT "DARTMOUTH BALL ON ITS OWN 20."
220 LET P = 1
240 LET X = 20
260 LET X1 = 20
280 LET D = 1
300 GOTO 2300
320 PRINT "NEXT PLAY";
340 INPUT Z
360 LET R = RND(Z)
362 LET R = R*(.97+P*.03)
370 LET T = T+1
372 IF T < 50 THEN 380
374 IF RND(Z) > .2 THEN 380
375 PRINT
376 PRINT "END OF GAME ***"
377 PRINT "FINAL SCORE: DARTMOUTH" S(2); "PRINCETON" S(0)
378 STOP
380 LET R1 = RND(Z)
400 LET F = 0
420 IF Z > 4 THEN 520
440 IF Z = 1 THEN 620
460 IF Z = 2 THEN 700
470 PRINT "PASS PLAY"
480 IF Z = 3 THEN 820
500 GOTO 1140
520 REM PUNT
540 LET Y = INT(100*(R-.5)^3+35)
545 IF Z = 7 THEN 5000
550 IF D = 4 THEN 560
555 LET Y = INT(Y*1.3)
560 PRINT "PUNT GOOD FOR" Y; "YARDS"
562 IF D<4 THEN 580
564 LET Y1 = INT(R1^2*20)+(1-P)*INT(R^2*30)
566 PRINT "RUN BACK FOR " Y1; "YARDS"
568 LET Y = Y-Y1
580 LET F = -1
600 GOTO 1480
620 REM SIMPLE RUN
630 PRINT "RUNNING PLAY"
640 LET Y = INT(24*(R-.5)^3+3)
660 IF R1 < .05 THEN 760
680 GOTO 1260
700 REM TRICKY RUN
710 PRINT "RUNNING PLAY"
720 LET Y = INT(20*R-5)
740 IF R1 > .1 THEN 1260
760 LET F = -1
780 PRINT "*** FUMBLE AFTER ";
800 GOTO 1260
820 REM SHORT PASS
840 LET Y = INT(60*(R1-.5)^3+8)
860 IF R < .05 THEN 960
880 IF R < .15 THEN 1080
900 IF R < .55 THEN 1020
920 PRINT "COMPLETE. ";
940 GOTO 1260
960 PRINT "INTERCEPTED. "
980 LET F = -1
1000 GOTO 1480
1020 PRINT "INCOMPLETE. ";
1040 LET Y = 0
1060 GOTO 1260
1080 PRINT "PASSER TACKLED. ";
1100 LET Y = - INT(10*R1)
1120 GOTO 1260
1140 REM LONG PASS
1160 LET Y = INT(160*(R1-.5)^3+30)
1180 IF R < .1 THEN 960
1200 IF R < .25 THEN 1080
1220 IF R < .70 THEN 1020
1240 GOTO 920
1260 REM RESULT OF PLAY
1280 LET X2 = X + P*Y
1300 IF X2 >= 100 THEN 1640
1320 IF X2 <= 0 THEN 2380
1340 IF Y < 0 THEN 1420
1360 IF Y = 0 THEN 1460
1380 PRINT "GAIN OF " Y "YARDS"
1400 GOTO 1480
1420 PRINT "LOSS OF " -Y; "YARDS"
1440 GOTO 1480
1460 PRINT "NO GAIN"
1480 LET X = X + P*Y
1500 IF X <= 0 THEN 2380
1520 IF X > 50 THEN 1580
1540 PRINT "BALL ON DARTMOUTH " X; "YARD LINE."
1560 GOTO 1940
1580 IF X >= 100 THEN 1640
1600 PRINT "BALL ON PRINCETON " 100-X ; "YARD LINE."
1620 GOTO 1940
1640 IF P < 0 THEN 1780
1660 IF F < 0 THEN 1740
1680 PRINT "TOUCHDOWN***"
1700 LET P = -1
1710 GOSUB 4300
1720 GOTO 2180
1740 PRINT "TOUCHBACK FOR PRINCETON***"
1760 GOTO 2180
1780 IF F < 0 THEN 1900
1800 PRINT "SAFETY***"
1810 GOSUB 4100
1820 PRINT "DARTMOUTH GETS BALL ON ITS OWN 40."
1840 LET X = 40
1860 LET P = 1
1880 GOTO 2220
1900 PRINT "TOUCHDOWN DARTMOUTH ***"
1910 GOSUB 4300
1920 GOTO 2180
1940 LET D = D+1
1960 IF F >= 0 THEN 2120
1980 IF P > 0 THEN 2060
2000 PRINT "DARTMOUTH'S BALL"
2020 LET P = 1
2040 GOTO 2220
2060 PRINT "PRINCETON'S BALL"
2080 GOTO 2210
2120 IF P*(X-X1)>=10 THEN 2220
2140 IF D < 5 THEN 2300
2150 IF P<0 THEN 2000
2160 GOTO 2060
2180 LET X = 80
2200 PRINT "PRINCETON BALL ON ITS OWN 20."
2210 LET P = -1
2220 LET D = 1
2240 PRINT "FIRST DOWN***"
2242 IF P < 0 THEN 2250
2244 IF X < 90 THEN 2260
2246 LET X1 = 90
2248 GOTO 2320
2250 IF X > 10 THEN 2260
2252 LET X1 = 10
2254 GOTO 2320
2260 LET X1= X
2280 GOTO 2320
2300 PRINT "DOWN " D; "AND " 10 + P*(X1-X); "YARDS TO GO."
2320 PRINT
2340 IF P > 0 THEN 320
2360 GOTO 2680
2380 IF F < 0 THEN 2580
2400 IF P > 0 THEN 2480
2420 PRINT "TOUCHDOWN***"
2440 LET P = 1
2450 GOSUB 4300
2460 GOTO 200
2480 PRINT "SAFETY***"
2490 GOSUB 4100
2500 PRINT "PRINCETON GETS BALL ON ITS OWN 40."
2520 LET X = 60
2540 LET P = -1
2560 GOTO 2220
2580 IF P > 0 THEN 2640
2600 PRINT "TOUCHBACK FOR DARTMOUTH."
2620 GOTO 200
2640 PRINT "TOUCHDOWN PRINCETON ***"
2650 GOSUB 4300
2660 GOTO 200
2680 REM PRINCETON OFFENSE
2700 LET P = -1
2720 IF D > 1 THEN 2840
2740 IF RND(Z) > 1/3 THEN 2800
2760 LET Z = 3
2780 GOTO 3120
2800 LET Z = 1
2820 GOTO 3120
2840 IF D < 4 THEN 2920
2860 IF X <= 30 THEN 2910
2880 LET Z = 5
2900 GOTO 3120
2910 IF 10 + X -X1 < 3 THEN 2740
2912 LET Z = 7
2914 GOTO 3120
2920 IF 10+X-X1 < 5 THEN 2740
2940 IF X > X1 THEN 3060
2960 IF RND(Z) > 1/2 THEN 3020
2980 LET Z = 2
3000 GOTO 3120
3020 LET Z = 4
3040 GOTO 3120
3060 IF RND(Z) > 1/4 THEN 3100
3080 GOTO 2980
3100 GOTO 3020
3120 GOTO 360
4000 REM KEEP SCORE
4100 LET S(1-P) = S(1-P)+2
4200 PRINT "SCORE: " S(2); "TO " S(0)
4210 PRINT
4220 RETURN
4300 IF RND(Z) > .8 THEN 4350
4310 PRINT "KICK IS GOOD"
4320 LET S(1-P) = S(1-P)+7
4330 GOTO 4200
4350 PRINT "KICK IS OFF TO THE SIDE"
4360 LET S(1-P) = S(1-P)+6
4370 GOTO 4200
5000 REM FIELD GOAL
5001 PRINT "PLACE KICK"
5005 LET F = -1
5006 IF R > .5 THEN 5010
5007 PRINT "KICK IS BLOCKED***"
5008 LET Y = -5
5009 GOTO 1480
5010 IF P < 0 THEN 5200
5020 IF X+Y >= 110 THEN 5100
5030 IF X + Y < 80 THEN 5060
5040 PRINT "KICK IS OFF TO THE SIDE."
5050 GOTO 1740
5060 PRINT "KICK IS SHORT."
5070 GOTO 1480
5100 PRINT "FIELD GOAL ***"
5110 LET S(2) = S(2)+3
5120 GOSUB 4200
5130 GOTO 2180
5200 IF X-Y <= -10 THEN 5300
5210 IF X-Y > 20 THEN 5060
5220 PRINT "KICK IS OFF TO THE SIDE."
5230 GOTO 2600
5300 PRINT "FIELD GOAL ***"
5310 LET S(0) = S(0)+3
5320 GOSUB 4200
5330 GOTO 200
9999 END
local ok, basic = pcall(require,"basic")
if not ok then
local h = http.get("https://gist.githubusercontent.com/MineRobber9000/7d735c2cd6620760670b9658760b4790/raw/89802963153be1901cc40454772d11beaa9b2ece/basic.lua")
local contents = h.readAll()
h.close()
package.preload["basic"] = loadstring(contents)
basic = require"basic"
end
local h = http.get("https://gist.githubusercontent.com/MineRobber9000/7d735c2cd6620760670b9658760b4790/raw/89802963153be1901cc40454772d11beaa9b2ece/ftball.bas")
local ftball = h.readAll()
h.close()
basic.run(basic.parser(basic.lexer(ftball)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment