Last active
August 29, 2024 17:38
-
-
Save MineRobber9000/7d735c2cd6620760670b9658760b4790 to your computer and use it in GitHub Desktop.
Dartmouth BASIC interpreter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local 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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local 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