Espen

Vote v1.0 for CC without adv. computers

Nov 9th, 2012
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.62 KB | None | 0 0
  1. --[[
  2. Vote v1.0 for CC without advanced computers by Espen
  3. An example code for a voting system, inspired by ewart4fun
  4.  
  5. Thread: http://www.computercraft.info/forums2/index.php?/topic/5807-lua-voting-program/
  6. --]]
  7.  
  8. -- [[ BEGINNING of FUNCTION DEFINITIONS ]] ---------------------------
  9. -- Writes text centered, x- and y-axis position can be offset, and the line to be written can be cleared beforehand.
  10. local function writeCentered( sText, nOffsetX, nOffsetY, color, bClearLine )
  11.     local maxX, maxY = term.getSize()
  12.    
  13.     if nOffsetX == null then nOffsetX = 0 end
  14.     local centeredX = (maxX / 2) - (string.len( sText ) / 2) + nOffsetX
  15.    
  16.     if nOffsetY == null then nOffsetY = 0 end
  17.     local centeredY = (maxY / 2) + nOffsetY
  18.    
  19.     term.setCursorPos( centeredX, centeredY )
  20.     if bClearLine then term.clearLine() end
  21.     write( sText )
  22. end
  23.  
  24.  
  25. --[[
  26.     Returns:
  27.         0 - If login is ok.
  28.         1 - If login failed.
  29.         2 - If user already voted.
  30. ]]
  31. local function checkLogin( sUser, sPwd )
  32.     --[[
  33.         ^%a     = first char has to be a letter
  34.         %w*     = then there can follow an arbitrary number of alphanumeric characters
  35.         :       = then a colon follows (which is used in the passwd file to delimit the usernames from their passwords)
  36.         [01]    = then either a 0 or a 1 follows
  37.         :       = then another colon follows (which is used in the passwd file to delimit the usernames from their passwords)
  38.         .*$     = finally the pattern ends with an arbitrary number of any characters, i.e. empty passwords are allowed as well (use .+$ to ignore users with empty passwords).
  39.        
  40.         ( )     = Everything we encase in brackets will be extracted and returned as a separate value.
  41.     ]]
  42.     local credentials_pattern = "^(%a%w*):([01]):(.*)$" -- Example: "user123:0:secret"
  43.     local bLoginOk = -1
  44.    
  45.     local hFile = fs.open( ".passwd", "r" )
  46.     local line = hFile.readLine()
  47.     while line do
  48.         local user, hasVoted, pwd = string.match( line, credentials_pattern )
  49.         if ( user and pwd ) and ( sUser == user ) then
  50.             if ( sPwd == pwd ) then
  51.                 if ( hasVoted == "0" ) then
  52.                     -- User found and password correct. Has not yet voted.
  53.                     bLoginOk = 0
  54.                     break
  55.                 else
  56.                     -- User found and password correct. Has already voted.
  57.                     bLoginOk = 1
  58.                     break
  59.                 end
  60.             else
  61.                 -- Password incorrect.
  62.                 --bLoginOk = -1  -- Unnecessary in the current code, as bLoginOk will not have changed from -1 when the program reaches this point.
  63.                 break
  64.             end
  65.         end
  66.        
  67.         -- Read the next line.
  68.         line = hFile.readLine()
  69.     end
  70.    
  71.     hFile:close()
  72.    
  73.     return bLoginOk
  74. end
  75.  
  76. local function getLogin()
  77.     local usrCurPosX, usrCurPosY, pwdCurPosX, pwdCurPosY
  78.     local username = "", password
  79.    
  80.     while username == "" do
  81.         writeCentered( "Username: ", -5, 0, nil, true )
  82.         usrCurPosX, usrCurPosY = term.getCursorPos()
  83.         writeCentered( "Password: ", -5, 1, nil, true )
  84.         pwdCurPosX, pwdCurPosY = term.getCursorPos()
  85.        
  86.         term.setCursorPos( usrCurPosX, usrCurPosY )
  87.         username = read()
  88.         if username == "" then term.clear() end
  89.     end
  90.    
  91.     term.setCursorPos( pwdCurPosX, pwdCurPosY )
  92.     password = read("*")
  93.    
  94.     return username, password
  95. end
  96.  
  97. -- Returns a table with candidates.
  98. local function getCandidates()
  99.     --[[
  100.         [^:]+   = Each candidate name has to be comprised of at least one character, except colon.
  101.     ]]
  102.     local candidate_pattern = "[^:]+"
  103.     local tCandidates = {}
  104.     local candidate = nil
  105.    
  106.    
  107.     local hFile = fs.open( ".candidates", "r" )
  108.     local line = hFile.readLine()
  109.     while line do
  110.         candidate = string.match( line, candidate_pattern )
  111.        
  112.         if candidate then
  113.             table.insert( tCandidates, candidate )
  114.         end
  115.        
  116.         -- Read the next line.
  117.         line = hFile.readLine()
  118.     end
  119.    
  120.     hFile:close()
  121.     return tCandidates
  122. end
  123.  
  124. local function printVotingScreen( candidateList )
  125.     term.clear()
  126.     term.setCursorPos(1, 2)
  127.     print( "Place your vote (type the corresponding numbers):\n" )
  128.     for index, candidate in ipairs( candidateList ) do
  129.         print( "\t("..index..") - "..candidate )
  130.     end
  131.     print( "\n\t(X) - Logout (vote later)." )
  132. end
  133.  
  134. local function getVote( candidateList )
  135.     while true do
  136.         printVotingScreen( candidateList )
  137.        
  138.         local _, sChoice = os.pullEvent( "char" )
  139.         local nChoice = tonumber( sChoice )
  140.        
  141.         -- Ask for confirmation of choice.
  142.         if candidateList[ nChoice ] then
  143.             write( "\nYou chose: ")
  144.             print (candidateList[ nChoice ] )
  145.             print( "(A)ccept or (C)ancel this choice." )
  146.             while true do
  147.                 local _, sCommit = os.pullEvent( "char" )
  148.                
  149.                 if sCommit and string.lower(sCommit) == "a" then return nChoice end
  150.                 if sCommit and string.lower(sCommit) == "c" then break end
  151.             end
  152.         end
  153.        
  154.         -- Logout
  155.         if sChoice and string.lower(sChoice) == "x" then break end
  156.     end
  157. end
  158.  
  159. local function setHasVoted( voter )
  160.     local users = {}
  161.     local username, hasVoted, password
  162.     local credentials_pattern = "^(%a%w*):([01]):(.*)$"
  163.    
  164.     -- Read old values into table 'users'.
  165.     local hFile = fs.open( ".passwd", "r" )
  166.     local line = hFile.readLine()
  167.     while line do
  168.         username, hasVoted, password = string.match( line, credentials_pattern )
  169.         if username and hasVoted and password then
  170.             users[username] = { hasVoted, password }
  171.         end
  172.         line = hFile.readLine()
  173.     end
  174.     hFile.close()
  175.    
  176.     -- Write changes to file.
  177.     local hFile = fs.open( ".passwd", "w" )
  178.     for user, _ in pairs(users) do
  179.         if user == voter then
  180.             hFile.writeLine(user..":1:"..users[user][2])
  181.         else
  182.             hFile.writeLine(user..":"..users[user][1]..":"..users[user][2])    -- users[user][1] is hasVoted and users[user][2] is password.
  183.         end
  184.     end
  185.     hFile.close()
  186. end
  187.  
  188. local function applyVote( tCandidateList, sVoter, nCandidateNum )
  189.     local vote = nil
  190.     local votes = {}
  191.     local votedCandidate
  192.     local votes_pattern = "^([^:]+):(%d+)$" -- Example: candidate3:27
  193.    
  194.     local hFile = fs.open( ".votes", "r" )
  195.     local line = hFile.readLine()
  196.     while line do
  197.         candidate, vote = string.match( line, votes_pattern )
  198.         if candidate and vote then votes[candidate] = vote end
  199.         line = hFile.readLine()
  200.     end
  201.    
  202.     votedCandidate = tCandidateList[ nCandidateNum ]
  203.     if not votedCandidate then print(tCandidateList[ 1 ]) error( "The voted candidate isn't in the list of eligible candidates. This shouldn't happen, please fix me." ) end
  204.    
  205.     -- Initialize votes for candidate in case there are not votes for him yet.
  206.     if not votes[votedCandidate] then
  207.         votes[votedCandidate] = 0
  208.     end
  209.    
  210.     -- Now finally increment his votes by 1.
  211.     votes[votedCandidate] = votes[votedCandidate] + 1
  212.    
  213.     -- Write the changes back to file.
  214.     local hFile = fs.open( ".votes", "w" )
  215.     for candidate, vote in pairs(votes) do
  216.         hFile.writeLine( candidate..":"..vote )
  217.     end
  218.     hFile.close()
  219.    
  220.     -- Set the hasVoted flag for the voter.
  221.     setHasVoted( sVoter )
  222. end
  223.  
  224. local function main()
  225.     term.clear()
  226.     local sUser, sPassword
  227.     local candidateList
  228.     local vote
  229.     local loginState
  230.     local validLogin = false
  231.  
  232.     -- Check for valid user.
  233.     while not validLogin do
  234.         sUser, sPassword = getLogin()
  235.         -- Special login which quits the program to console. Remove if unwanted.
  236.         if sUser == "exit to" and sPassword == "console" then return false end
  237.        
  238.         loginState = checkLogin( sUser, sPassword )
  239.        
  240.         if loginState == 0 then
  241.             writeCentered( "[ Access Granted ]\n", 0, 3, colors.lime, true )
  242.             validLogin = true
  243.         elseif loginState == -1 then
  244.             writeCentered( "[ Access Denied ]\n", 0, 3, colors.red, true )
  245.         elseif loginState == 1 then
  246.             writeCentered( "[ Already Voted ]\n", 0, 3, colors.purple, true )
  247.         end
  248.        
  249.         sleep(1)    -- artificial cooldown before next try
  250.     end
  251.  
  252.     -- Get the list of candidates and let the current user make a vote.
  253.     candidateList = getCandidates()
  254.     if #candidateList < 1 then
  255.         term.clear()
  256.         writeCentered( "No candidates to vote for." )
  257.         writeCentered( "Please try again later.", 0, 1 )
  258.         writeCentered( "Press ENTER to dismiss...", 0, 4 )
  259.         local _, enter
  260.         while enter ~= 28 do
  261.             _, enter = os.pullEvent( "key" )
  262.         end
  263.         return true
  264.     end
  265.    
  266.     -- Get a vote and apply it.
  267.     vote = getVote( candidateList )
  268.     if type(vote) == "number" then
  269.         applyVote( candidateList, sUser, vote )
  270.         term.clear()
  271.         writeCentered( "Thank you for voting.", 0, 0, colors.yellow )
  272.         writeCentered( "Have a nice day!", 0, 1, colors.yellow )
  273.         sleep(3)
  274.     end
  275.    
  276.     return true
  277. end
  278. -- [[ END of FUNCTION DEFINITIONS ]] ---------------------------
  279.  
  280. -- Prevent termination key-combo
  281. nativePullEvent = os.pullEvent
  282. os.pullEvent = os.pullEventRaw
  283.  
  284. -- Program loop
  285. local running = true
  286. while running do
  287.     running = main()
  288. end
  289.  
  290. -- Restore native os.pullEvent
  291. os.pullEvent = nativePullEvent
Advertisement
Add Comment
Please, Sign In to add comment