Stories
Slash Boxes
Comments

SoylentNews is people

Log In

Log In

Create Account  |  Retrieve Password


Voting Script 3 - Borda Count

Posted by prospectacle on Sunday March 30 2014, @08:44AM (#241)
0 Comments
Code

Here's a third version of my voting program. Unlike the previous version, it doesn't allow duplicate ranks (you can't rank two candidates as equal first, or equal second, etc).

It can be run on a set of text-based votes, e.g. emails or forum-comments. It recognises and counts valid votes, and filters out invalid data.

It gives a score to each candidate, based on the rank you give it. It is effectively a "Borda Count" voting system (http://en.wikipedia.org/wiki/Borda_count). Version 2 used "Range Voting" and version 1 used "Approval Voting".

I've also tidied the code up a bit, to make it easier to read and simpler to use.

The code below contains example data so you can run it as is, to get an idea of how it works.

<?php

/* How to use this script:

1 - Ask people to write votes that look like this:
    some candidate name = 1
    some other = 2
    another_one = 4
    Any other text will just be ignored.
    Any invalid = votes will be ignored, too
2 - Collect votes. e.g. via email, forum-comments, or a special web-form.
3 - Put all the votes in an array. Each vote should contain its vote-text, and a User ID.
4 - Run this script to filter, parse and count the votes.

*/

// Example candidates:
$valid_candidates = array(
    "candidateone",
    "another candidate",
    "yet another option",
    "somethingelse");

// Example votes:
$votes_array = array(
    // Upper case or lower case doesn't matter.
    array(
        "user_id"=>234,
        "text"=>"
            candidateOne = 1
            Another Candidate = 2
            SomethingElse = 3
        "),
    // Duplicate user. This will be handled properly.
    array(
        "user_id"=>234,
        "text"=>"
            Oops forgot one I like:
            Yet Another Option = 4
            Did I mention:
            CandidateOne = 1
        "
        ),
    // This one contains mostly invalid rankings, and one valid one.
    array(
        "user_id"=>345,
        "text"=>"
            // I hate CandidateOne
            CandidateOne = 6
            Another Candidate = 1
            Yet Another Option = 1
            My friend who's not listed = 3
        ")
    );

// Some options on how the votes are counted.
$allow_duplicate_ranks = false;
$allow_write_in_candidates = false;

// If you allow write-in candidates, specify a maximum possible rank.
// Otherwise the maximum rank equals the number of candidates.
if ($allow_write_in_candidates) $maximum_rank = 10;
else $maximum_rank = count($valid_candidates);

// put valid-user filter in here if necessary
function valid_user($user_id){return true;}

// Arrays to store the counted votes in:
$votes_by_voter = array();
$votes_by_candidate = array();

// Process all votes
foreach ($votes_array as $vote)
{

  // Is it a valid registered user?
  if (valid_user($vote["user_id"]))
  {

    // Process each line of the vote
    $vote_lines = explode("\n", trim($vote["text"]));
    foreach ($vote_lines as $this_line)
    {

      // Does it have an equals sign
      $equals_sign = strpos($this_line, "=");
      if ($equals_sign !== false)
      {

        // Does it have only one equals sign?
        $cleaned_up_line_text = trim($this_line, ";.!\t\n\r\0");
        $parts_of_line = explode("=", $cleaned_up_line_text);
        if (count($parts_of_line) == 2)
        {

          // Get the candidate and rank, make sure they're valid.
          $candidate = strtolower(trim($parts_of_line[0]));
          $candidate_is_valid = in_array($candidate, $valid_candidates);
          $rank = intval(trim($parts_of_line[1]));
          $rank_is_valid = ( ($rank > 0) && ($rank <= $maximum_rank) );

          // Proceed if (it's a valid rank number) and
          // (the candidate is valid, or we're allowing write-in candidates).
          if (($rank_is_valid) && ($candidate_is_valid || $allow_write_in_candidates))
          {
            // Get the score for this candidate.
            // The score is: maximum_rank - (this_rank - 1).
            // For example:
            // - Say there are 5 candidates and the maximum rank is 5
            // - A rank of 1 give it a score of 5.
            // - A rank of 2 gives it a score of 4.
            // - A rank of 5 gives a score of 1.
            // See "Borda Count".
            $score = $maximum_rank - ($rank-1);

            // If this is the voter's first vote, create a voting-record for them.
            // This keeps track of which candidates and ranks they've already voted.
            $voter = $vote["user_id"];
            if (!isset($votes_by_voter[$voter]))
            {
              $votes_by_voter[$voter]["candidates"] = array();
              $votes_by_voter[$voter]["ranks"] = array();
            }

            // Make sure this user hasn't already voted on this candidate
            if (!isset($votes_by_voter[$voter]["candidates"][$candidate]))
            {

              // Make sure the user hasn't already assigned this rank number,
              // or that we're allowing duplicate ranks.
              if ($allow_duplicate_ranks || (!isset($votes_by_voter[$voter]["ranks"][$rank])))
              {

                // Remember that this voter has voted for this candidate,
                // and has used up this rank.
                $votes_by_voter[$voter]["candidates"][$candidate] = true;
                $votes_by_voter[$voter]["ranks"][$rank] = true;

                // Count the vote towards the total for this candidate.
                if (!isset($votes_by_candidate[$candidate]))
                  $votes_by_candidate[$candidate] = $score;
                else $votes_by_candidate[$candidate] += $score;

              } // End of checking if this rank is a duplicate for this voter.
            } // End of check checking if candidate is a duplicate for this voter.
          } // End of check for valid vote values.
        } // End of check for correctly formatted vote
      } // End of check for equals sign
    } // End of for loop for lines of vote text.
  } // of check for valid user.
} // end of for loop for all votes.

print "Who have voters voted for, and which ranks have they used?:<pre>";
print_r($votes_by_voter);
print "</pre><Br>";
print "What score does each candidate end up with<pre>";
// Sort the candidates from highest to lowest
arsort($votes_by_candidate);
print_r($votes_by_candidate);
print "</pre>";

?>

crunch has been re-tasked

Posted by crutchy on Saturday March 29 2014, @02:14PM (#239)
0 Comments
Code

no more searching

reset color:

~color -1

bold white:

~color 00

change color per mirc values: http://www.mirc.com/colors.html

~color 01

thru

~color 15

requote last in weird and wonderful ways (or show about):

~

bot doesn't quote itself (shows about)
atm only verbs ending in "ing" and a small set of nouns recognised, but this will grow

if you're interested in contributing (even just to the arrays) have a squiz at:
https://github.com/crutchy-/test/blob/master/bacon.php

anyone new to git, have a squiz at http://wiki.soylentnews.org/wiki/User:Crutchy#Git.2FGitHub
you can also edit directly on github (ideally only for simple changes such as additions to arrays).

todo: add collective noun substitution
todo: add ability to append arrays from within irc

thanks heaps mrbluze... ideas man and english extraordinaire

Overzealous down-moderators!

Posted by wjwlsn on Thursday March 27 2014, @07:20PM (#235)
31 Comments
Soylent

I'm seeing a lot of unwarranted (IMO) down-moderation lately, mostly on posts that express a minority opinion or that question a majority opinion (judging minority/majority based on discussion context). As a result, there are many posts ranked -1 or 0 that probably deserve higher scores.

I'd like to remind moderators that you're supposed to "Concentrate more on promoting than demoting". In the meantime, I'm going to spend all my mod points on posts that I think have been modded down unfairly. I encourage others to consider spending some mod points in this fashion as well.

crunch irc search bot

Posted by crutchy on Thursday March 27 2014, @12:18PM (#233)
0 Comments
Code

https://github.com/crutchy-/test/blob/master/crunch.php

designed to quote either the last thing said by a nick or the last thing said by a nick containing a search query

usage:
~
quotes a little about string including github source link
~q or ~quit
tells bot to quit
~find nick
quotes last thing said by nick (in local recorded log files)
~find nick query
quotes last thing said by nick that contains query (in local recorded log files)

code is fairly short and (hopefully) sweet. no comments sorry.

TODO: search online logs @ http://logs.sylnt.us/

Taking a slice of Markov Music Pi

Posted by gishzida on Thursday March 27 2014, @06:37AM (#231)
1 Comment
Code

A Soylent News story posted last Saturday got me to thinking about the potential for a Markov chain based music "toy" application. Understand that at this moment I don't quite have the skill to write this app but it is an interesting thought experiment... so I'm writing it down here.

Yes I realize that you can do a lot of things with Max [$400!] but that is outside my budget [$0]... OTOH CSound is free but is a primarily sound design software suite rather than a composition application... tho' I have found some interesting things that I might investigate...

Most of the Pi based music I have seen / heard is based upon using the numbers 0 through 9 in the Pi sequence to correspond to a single note in a key. An example is the pi10k flash app.

The Markov Sliced Pi idea is to take a file with n number of digits of Pi and run a n-gram analysis where n=2. The result gives you the probability of two digit sequences of 00 to 99.

With this one can then do a number of interesting experimental musical things:

1) Using these digits as midi note numbers, and then picking a note at random, a note sequence of arbitrary length can be generated in a note rage of C0 to D#8 [greater than the range of a piano]. This will probably sound chaotic.

2) Add a "key Filter" which will drop notes that are not in the "key" of the starting note. For example if the starting not is C3= midi not number 36 then any note that does not fall in the Key of C [C D E F G A B] would be dropped from musical playback.

3) Add a "Shift filter" to shift discarded notes to be played in the relative minor or other key related shift [i.e. the idea is to force the output stream to sound "musical". While this might sound like twisting the input stream one might use pi or tau as a means to shift the note

3a) Modify the shift filter to work on notes which fall off of the circle of fifths for the key the song is played. this would prevent "non-harmonic notes"

4) Add additional midi note channels and assign octave ranges to specific instruments. Assuming that you had 4 instrument channels the first billion digits of Pi played at 1 second per note, the composition should last at least 3.96 years at 24 x 7 x 365.25. Generally normal performances are not this long. but once one had the software script written it would be the ultimate in elevator music as it would be an ever changing tune

5) Add a filter which forces the note stream into an 8 or 16 note Sequencer of notes. This causes "patterned musicality". This is done by taking the next 8 or 16 notes of a instrument and playing them until the next 8 or 16 notes are captured. The process could then be repeated until you run out of notes.

6) Add a Chord construction algorithm / filter / sequencer that builds chords much in the same way that the filter / sequencer operates. Take 3 notes, construct a chord, play it until the buffer files again. Variation between single notes and the chord may be based upon how far apart in the note sequence they are.

7) Run the Markov filter again and this time use n=4. this will give two note [or chord] sequences

7a) Run the Markov filter again and this time use n=6. this will give three note [or chord] sequences

8) use 7) and 7a) to build a Markov chain based Chord patterns using the circle of fifths.

Of course this is all a written out thought experiment on some of the things which might be done by crossing Markov Chains and Pi... since I am the lazy guy I am [and get easily distracted] it remains to be seen if I will get around to doing them.

A Pleasant Vacation

Posted by mcgrew on Wednesday March 26 2014, @04:38PM (#228)
0 Comments
News

I'd planned on traveling to Cincinnati last Monday to visit my daughter and came down with the flu. I called Patty and told her it would be the next Monday; she works full time and is a full time student at Cincinnati State, and Monday is the only day she has off.

I looked her address up on Google Maps. It looked pretty easy to find. "Don't trust Google," Patty said. "They're doing road construction and it will try to send you down a road that's closed. Take the Hoppit exit, turn right and I'll meet you at the Shell station.

My nose was still producing copious amounts of snot, I was still coughing up lots of mucus but felt a hell of a lot better than I had last week. I woke up about 5:30 Monday morning, did my morning routine functions, especially coffee, one function of which was checking my phone. Three missed calls and a voicemail from Patty. I called, knowing she wouldn't answer because she's never awake that early and left a message that I was on my way and to call when she woke up.

I have a big laptop bag and a small laptop; the bag had cost me $5 and came with a broken laptop. I put spare clothing, charging accessories in it and loaded it, my battery jumper, and Patty's cat's ashes in the car.

I had a half tank of gas and figured it would get me to Indiana, where fuel would surely be cheaper. After all, it's a red state and Republicans hate taxes, right? No such luck, I was down to an eighth of a tank by the time I reached Bloomington.

It's a little frustrating that Cincinnati is southeast of Springfield, but you have to go northeast to get there unless you want to drive over three hundred miles of two lane road with 30 to 45 MPH speed limits and lots of stop signs and so forth. It would take forever that way.

Gas was a nickle cheaper than Springfield; $3.55. I put twenty bucks in, figuring I'd fill up in Indiana and started on my way again. I had my phone plugged into the car stereo for times there was no music and I'd heard all the CDs, which I'd neglected to change before I left. There was a rest area so I stopped to urinate and change CDs. I checked the phone; Patty had called. I called back, and again she warned me about Google.

Apparently people from Illinois aren't welcome in Indiana, as the usual "Welcome to [state]" sign was nowhere in evidence. The only way I knew I'd crossed state lines was that the pavement got a lot worse. I-74 had apparently been badly neglected for years in Indiana, except for a stretch by Indianapolis. Gasoline was more expensive than at home.

The sun was shining, the pavement was dry, and there was little traffic. "Welcome to Ohio!" the big sign proudly proclaimed in bright graphics as the pavement improved. I reached Cincinnati and the traffic was terrible. I-74 East split into I-75 north and south; I guessed south but wasn't sure. I pulled over to the shoulder and called Patty to make sure I wasn't going the wrong way. I wasn't.

The next exit was the Hoppit exit. I met Patty at the gas station. "You shaved!" she said.

"Yeah, my upper lip hasn't seen the sun since before you were born." Patty had never seen me completely shaven; most of her life I've had a beard, or at least a mustache when my chin hair went gray.

"I don't like it," she said, frowning."

"Neither do I. I'm growing it back this fall." I noticed the gas cap door on her car was open as she pulled out and was about to honk to let her know when she pulled over and shut it.

We got to her apartment and we hugged and I shook her fiance's hand an gave Patty the metal box and envelopes. I hadn't opened one of them, which had come from Coble Animal Hospital. I'd thought it contained Princess' ashes but they called a week later to inform me I could pick her up.

"Ooh, this is a pretty box," she said. "What's in it?"

I still can't believe I spent over three hundred dollars for a dead cat, part for the vet to tell me she was dying and part to have her cremated, since the ground was frozen and I couldn't bury her. I discovered that animals and humans are cremated in the same crematorium, which is why it's so expensive. If Little One dies in the winter I'm storing her in a deep freeze until the ground thaws.

Patty opened the unopened envelope and started crying. It was a plastic placard that read "PRINCESS" and had her paw prints in it. No, I guess I didn't spend $300 on a dead cat, I spent it on my daughter. "Put this with Calie under the tree," she instructed. "When you move, take it and Calie's grave marker with you."

Colby had planned on making Reuben sandwiches for lunch but the corned beef was still frozen. "Let's go to Chick Filet," he said. "OK," I replied,"but then Patty needs a phone." Her iPhone had been broken for months, its screen cracked. And she'd liked my phone and especially liked my low phone bill.

We had chicken sandwiches and went to Best Buy. The price of the phone was half what I'd paid for mine. She was trying to decide between it and a more expensive one with a front facing camera but decided she liked the idea of it being waterproof and resistant to shock.

"Lets buy a TV while we're here" she said to Colby. After they talked for a while she said "well, I'm buying a TV. I have the money." They have an old twenty two inch tube TV that doesn't work and a little nineteen inch widescreen.

But she didn't like the prices so we went to H.H. Gregg, whose prices were no better than Best Buy's. Best Buy's crack Geek Squad couldn't activate Patty's new phone so we took it home and did it ourselves.

I'd bought Gravity, which had come from Amazon amazingly the day before it was supposedly released for sale. It was a "combo pack" with a DVD, Blu-Ray and download. I'd brought the Blu-Ray for Patty, and we watched it using her Playstation and little TV set.

None of us had seen the previous night's Cosmos so she fired up Hulu plus on the Playstation. After watching it and an episode of Doctor Who I decided that I wanted Hulu Plus.

The next morning she gave me a big bowl of corned beef, cabbage, carrots, and potatoes, and two T shirts. One was almost a joke; a St. Patrick's Day Reds shirt. The other was hawking some video game, a nerdy shirt I'll wear proudly.

She wanted to see how badly Google would have set me astray so I gave her my phone. She was amazed. "They got it perfect, that's how I told you to go." I loaded up the car, we said our goodbyes and I set off on the long journey home.

The trip home was as unpleasant as the trip there had been pleasant. First, I missed my turn to get on I-74. Five miles later I got on I-75, saw I was headed to Dayton and took the next exit. I stopped at a gas station, got gas, and consulted the map.

It would be nice of these things came with manuals. I think it ironic that everything used to have a detailed manual when technology was primitive enough you didn't need one, and now that interfaces have only icons and no way to discern WTF they mean, they don't. Let's see, looks like I go that way...

The radio was playing commercials so I switched it to the phone to listen to KSHE. The disk jockey started giving directions! "Go west on" whatever street the gas station was on "point seven miles and turn right." It wasn't KSHE, it was Google Maps. It easily got me back on I-74 north and it wouldn't shut up so I switched back to the radio.

Traffic was horrible; a semi that read "TARGET" zoomed past me doing at least twenty miles above the speed limit and almost made me miss my exit. Looks like it isn't just their IT that could use more training.

A little green sign with white lettering said "Welcome to Indiana". It started snowing. Twenty miles later visibility was poor, and twenty minutes after that the pavement was covered.

It was a miserable trip. The snow stopped around Indianapolis and the traffic was almost as bad as Cincinnati. Halfway to Illinois the wind started blowing. A couple of semis almost got blown off the highway.

Gas in Bloomington was $3.49.

When I got home there was a box on my doorstep; The Paxil Diaries had arrived. I'd screwed it up terribly. So you still can't have a copy yet...

php irc bot for posting wiki content

Posted by crutchy on Tuesday March 25 2014, @12:29PM (#226)
1 Comment
Code

i was inspired to work on this after i saw mention of piping irc to the wiki @ http://wiki.soylentnews.org/wiki/CommunitySupport#Projects

it's been tested some but is still a work in progress.
getting around the anti-spam/anti-bot features of wiki is something i'll have to consult a wizard on.

https://github.com/crutchy-/test/blob/master/bot.php

i'm not a professional programmer so it probably sucks.
any criticisms etc are welcome, and if i can be bothered i may even take them on board, or you can do a pull request if you feel like having a play.

this is my first open source code file :-)

A bedtime story for A.I.s. in training. Last part posted

Posted by gishzida on Monday March 24 2014, @10:15AM (#223)
0 Comments
Career & Education

The last part of my fable for I.T. workers has been posted on my blog.

Nobots News

Posted by mcgrew on Sunday March 23 2014, @05:24PM (#221)
0 Comments
News

If you're the owner of a copy of Nobots, you now own a rare book. Fewer than two dozen were printed. If you don't yet have a copy, the price is a little higher.

When I originally published I was brand-new to all of this. I guess I still am. Until now the only place it was for sale was Lulu; I hadn't properly registered its ISBN and the bar code on the cover was wrong (Lulu put it there).

When I was readying The Paxil DiariesI got better at navigating Lulu's interface and figured out how to add one of my ISBNs and get it for sale at Amazon, B&N, etc., and get it listed on Google Book Search. I fixed the front cover, too. It now looks like it does on my web site.

Those fewer than two dozen copies will be worth quite a bit in a few years. I worked with a fellow named (iirc) Dave Luttrell a couple of decades ago when computers were expensive. His sister won the lottery and fulfilled his dream of writing a book about his time in the Vietnam jungles. She bought him a computer for him to write it on, and a small local publishing house published it.

There was only a single printing, I don't know how big the print run was, but the local library had a copy. Interesting book, could have been better edited.

Years after I'd last seen Dave, Amy was telling me about her late uncle who had written a book about Vietnam and I realized that Dave was Amy's uncle. She was wishing she had a copy of his book and tried to find one.

The Elf Shelf, a used bookstore here, had a waterlogged copy for $250. So hang on to those books!

No sooner than I'd ordered a galley proof of The Paxil Diaries when I found a huge blunder -- a lot of chapter numbers were wrong and there were no page numbers. That's now fixed, and barring any further stupidity on my part you should be able to get a copy in a few weeks at the latest -- they shipped the galley proof three days ago.

Updated email-scraping voting system to allow preferences

Posted by prospectacle on Sunday March 23 2014, @02:34AM (#219)
9 Comments
Code

I've updated my voting system to allow preferential voting (the previous method uses approval voting). It gives a score to each candidate based on its rank. E.g. if there are 10 candidates, and you give a candidate 1st preference, it gets 10 points, second preference gets 9 points, etc.

It's therefore functionally equivalent to "range voting".

<?php

/* How to use:
    Put all emails in an array with values in $emails["text"] and $emails["user_id"];
    Put the list of valid candidates in the function valid_candidate();
    Put the check for user-authorisation in function valid_user();
    Enjoy.
*/

$emails_array = array(
    array("user_id"=>234, "text"=>"
            option1 = 1
            option3 = 2
            optionwhatever = 3
        "),
    // Duplicate user, will be handled correctly.
    array("user_id"=>234, "text"=>"
        Oops forgot one I like:
        Optionfour = 2
        // Did I mention:
        option1=1
        "
        ),
    array("user_id"=>1234,
        "text"=>"
        // I hate option1
        Option1 = 6
        option2 = 1
        ")
    );

function valid_user($user_id){return true;} // put user filter in here if necessary
function valid_candidate($name){ return true;} // is the name one of the candidates?

$number_of_options = 6;

// Process all emails
foreach ($emails_array as $email)
{

  // Is it a valid registered user?
  if (valid_user($email["user_id"]))
  {

    // Process each line of the email
    $email_lines = explode("\n", trim($email["text"]));
    foreach ($email_lines as $this_line)
    {
      // Does it have an '=' sign and only one = sign
      $equals_sign = strpos($this_line, "=");
      if ($equals_sign !== false)
      {
        $cleaned_up_line_text = trim($this_line, ";.!\t\n\r\0");
        $parts_of_line = explode("=", $cleaned_up_line_text);
        if (count($parts_of_line) == 2)
        {
            // Is it a valid candidate and rank?
            // Candidate is in lower case.
            $candidate = strtolower(trim($parts_of_line[0]));
            $rank = intval(trim($parts_of_line[1]));
            if (valid_candidate($candidate) && ($rank > 0) && ($rank <= $number_of_options))
            {
                // Get the score for this candidate.
                // The score is the number of options - how far it is ranked below 1.
                // e.g. a rank of 1 would give it a score of $number_of_options.
                // a rank of 2 gives it a score of $number_of_options -1.
                // See "range voting".
                $score = $number_of_options - ($rank-1);

                // Make sure this vote for this user hasn't already been cast
                if (!isset($user_votes[$email["user_id"]]) ||
                    !isset($user_votes[$email["user_id"]][$candidate]))
                {
                    // Remember this user has voted for this name already.
                    $user_votes[$email["user_id"]][$candidate] = true;

                    // Count the vote towards the total
                    if (!isset($candidate_votes[$candidate]))
                        $candidate_votes[$candidate]=$score;
                    else $candidate_votes[$candidate]+= $score;
                }
            } // end of check for valid vote values.
        } // of check for correctly formatted vote
      } // of check for equals sign
    } // End of for loop for lines of email
  } // of check for valid user.
} // end of for loop for all emails.

print "votes:<br>";
print_r($user_votes);
print "<br><Br>";
print "candiate_votes<Br>";
print_r($candidate_votes);

?>