Espen

Vote v1.0

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