This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

[SOLVED] File I/O Functions - appending scores

Help for those learning Tcl or writing their own scripts.
Post Reply
M
MIODude
Voice
Posts: 32
Joined: Mon Oct 09, 2006 6:26 pm

[SOLVED] File I/O Functions - appending scores

Post by MIODude »

hi - I'm making just a little hockey type game, but I don't know how to do two things.. I tried reviewing other scripts that do similar functions (like trivia...) but I get lost. I'm still a beginner with this stuff..

The script simulates a game.. and the end variables i need to keep are the $nick, $games, $goals, $assists, and $points

The file created is just a text file 'hockeystandings'

and it would be like this

Nick1 4 2 4 6 <--- nick, games, goals, assists, points.
Nick2 3 3 5 8
Nick3 7 2 9 11
etc


The problem I'm having is, it needs to first check if the person exists in the file.. If the person doesn't exist, it would add. If the person does exist, it would then combine the values already there, so that the numbers are a running total. Games would just increment (+1) everytime.
As well... when someone tries to do the standings, it would sort based on the points column.

I've read though the TCL faq (Basic File Operation) .... but its obvious its over my head.. i can't seem to figure out how to incorporate what they say in there..


This is my script so far : Right now, i have the standings just outputing regularly - not sorted..
My priority is to get the file to be updated and appended correctly - but I don't know enough of TCL

Code: Select all

# Olympic Hockey - By Rilly #
bind pub - !hockey hockey
bind pub - !standings standings
bind msg o newmonth newmonth
set hockeyversion "1.0"
set channel "#channel"

set countries {
"long list of countries"
}

set referees {
"refs"
}

set actions {
"bump"
"check"
"trip"
"slash"
"pokecheck"
"ooohhhh"
"wow did you see that save?"
"eewww injury!"
"cross-checking Ref"
"Ref? Are you blind?"
"penalty shot!"
"fight! fight!"
"boooorinnnng"
"crunch! He felt that hit"
"smack"
}

############### hockey game procedure
proc hockey {nick uhost hand chan args} {
if {![hockeythrottled $uhost:#channel 3600]} {
global countries referees actions channel
	set country1 [lindex $countries [rand [llength $countries]]]
	set country2 [lindex $countries [rand [llength $countries]]]
	set ref1 [lindex $referees [rand [llength $referees]]]
	set ref2 [lindex $referees [rand [llength $referees]]]
	set action1 [lindex $actions [rand [llength $actions]]]
	set action2 [lindex $actions [rand [llength $actions]]]
	set action3 [lindex $actions [rand [llength $actions]]]
	set action4 [lindex $actions [rand [llength $actions]]]
	set action5 [lindex $actions [rand [llength $actions]]]
	set action6 [lindex $actions [rand [llength $actions]]]
      if ![file exists "hockeystandings"] {
       set f [open "hockeystandings" w]
       puts $f "Rilly 0 0 0 0"
       close $f
      }
	set maxpoint 3
	set goalsfirst [rand $maxpoint]
	set goalssecond [rand $maxpoint]
	set goalsthird [rand $maxpoint]
	set assistsfirst [rand $maxpoint]
	set assistssecond [rand $maxpoint]
	set assiststhird [rand $maxpoint]
	set goals [expr $goalsfirst + $goalssecond + $goalsthird]
	set assists [expr $assistsfirst + $assistssecond + $assiststhird]
	set points [expr $goals + $assists]
	putquick "NOTICE $nick :H O C K E Y T I M E !"
       putquick "NOTICE $nick :Tonight's matchup is between your home country of $country1 versus the power house of $country2"
	putquick "NOTICE $nick :Tonight's referees are $ref1 and $ref2. Lets hope they keep this a fair game!"
	putquick "NOTICE $nick :$country1 lines up with their top player, $nick taking the faceoff"
	putquick "NOTICE $nick :And the first period starts!"
	putquick "NOTICE $nick :..... $action1... $action2...... BUUUUUZZZZZZZZZZZZ End Of First Period!"
	putquick "NOTICE $nick : You scored $goalsfirst goals and had $assistsfirst assists that period!"
	putquick "NOTICE $nick : The teams go to their respected dressing rooms for intermission!"
	putquick "NOTICE $nick :OK Intermission over.. $nick gets ready for the faceoff"
	putquick "NOTICE $nick :And the second period starts!"
	putquick "NOTICE $nick :..... $action3... $action4...... BUUUUUZZZZZZZZZZZZ End Of Second Period!"
	putquick "NOTICE $nick : You scored $goalssecond goals and had $assistssecond assists that period!"
	putquick "NOTICE $nick : The teams go to their respected dressing rooms for intermission!"
	putquick "NOTICE $nick :OK Intermission over.. $nick on the bench to start period 3, but I'm sure we'll eventually see $nick again"
	putquick "NOTICE $nick :And the third period starts!"
	putquick "NOTICE $nick :..... $action5... $action6...... BUUUUUZZZZZZZZZZZZ End Of the Game!"
	putquick "NOTICE $nick : You scored $goalsthird goals and had $assiststhird assists that period!"
        if [rand 2] {
		putquick "NOTICE $nick :Congratulations, $nick! You helped $country1 win the game! But this is just one game of many....."
		putquick "NOTICE $nick :On a personal note, you scored $goals goals and had $assists assists for a total of $points points!"
		putquick "NOTICE $nick :I will add those totals to your standings for the tournament."
	} else {
		putquick "NOTICE $nick :Sorry $nick, $country2 won the game, but you still played well. Remember, the next game will be coming up soon.................."
		putquick "NOTICE $nick :On a personal note, you scored $goals goals and had $assists assists for a total of $points points!"
		putquick "NOTICE $nick :I will add those totals to your standings for the tournament."
#		return 1
	}

	if {![file exists "hockeystandings"]} {
	set fd [open $hockeyscores w]
	close $fd
        }
	set fd [open "hockeystandings" r]
	set j 0
	while {![eof $fd]} {
	lappend hockeyplayer [gets $fd]
	set j [incr j]
        }
	set i [expr $j - 1]
	set hockeyplayer [lreplace $hockeyplayer $i $i]
	putquick "NOTICE $nick :$hockeyplayer is what variable hockeyplayer is equal too."
	close $fd
	for {set k 0} {$k < $i} {incr k 4} {
	set existingnick [lindex $hockeyplayer $k]
	if {$hand == $existingnick} {
	set games [expr [lindex $hockeyplayer [expr $k + 1]] + 1]
	set goals [expr [lindex $hockeyplayer [expr $k + 2]] + 1]
	set assists [expr [lindex $hockeyplayer [expr $k + 3]] + 1]
	set points [expr [lindex $hockeyplayer [expr $k + 4]] + 1]
	set hockeyplayer [lreplace $hockeyplayer [expr $k + 1] [expr $k + 2] [expr $k + 3] [expr $k + 4] $games $goals $assists $points]
	set dscore [lindex $hockeyplayer [expr $k + 1]]
	set hockeyplayer [lreplace $hockeyplayer 1 2 0 0]
	for {set k 1} {$k < $i} {incr k 2} {
	set hockeyplayer [lreplace $hockeyplayer $k $k 0]
	incr k
	set hockeyplayer [lreplace $hockeyplayer $k $k 0]
        }

}
	set gameplaying 0
	set chan ""
	set fd [open "hockeystandings" w]
	foreach line $hockeyplayer {
	puts $fd $line
}
	close $fd
return 0
}  
}
	set hockeyplayer [lappend hockeyplayer $hand]
	set hockeyplayer [lappend hockeyplayer 1]
	set hockeyplayer [lappend hockeyplayer 1]
	set fd [open "hockeystandings" w]
	foreach line $score {
	puts $fd $line
}
	close $fd
       putserv "NOTICE $nick :Sorry $nick - You need to wait 5 minutes between attempts!"
return 0
}

############### end of hockey game procedure





############ Monthly Reset procedure
proc newmonth {nick uhost hand chan args} {
global countries referees actions channel
set f [open "hockeystandings" w]
puts $f "Rilly 0 0 0 0"
close $f
putserv "privmsg $channel :Hockey Tournament has been reset! Type !hockey to play!"
return 1
}
############ End of Monthly Reset procedure

############# standings procedure.

proc standings {nick uhost hand chan args} {
global countries referees actions channel
putquick "privmsg $chan :\00306<<<<<<<<<<\00313O L Y M P I C * H O C K E Y * S T A N D I N G S\00306>>>>>>>>>>>\003"
putquick "privmsg $chan :\00309~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\003"
      set fd [open "hockeystandings" r]
      set j 0
      while {![eof $fd]} {
      gets $fd hockeyplayer
#      lappend hockeyplayer [gets $fd]
putquick "privmsg $chan :[lindex \00307$hockeyplayer\003 0] \00310has played [lindex $hockeyplayer 1] games with [lindex $hockeyplayer 2] goals, [lindex $hockeyplayer 3] assists, for a total of [lrange $hockeyplayer 4 end] points\003"
#      putserv "notice $nick : $hockeyplayer hockeyplayer variable within j loop"
      incr j
      }
      close $fd
}
#      set i [expr $j - 1]
#      set hockeyplayer2 [lindex $hockeyplayer $i]
#      putquick "notice $nick : $hockeyplayer2 hockeyplayer variable after lreplace"
#      close $fd
#      set looptest [llength $hockeyplayer]
#      for {set k 0} {$k < $looptest} {incr k 5} {
#      set wosnick [lindex $hockeyplayer $k]
#      putquick "notice $nick : $wosnick nick"
#      set games [lindex $hockeyplayer [expr $k + 1]]
#      putquick "notice $nick : $games games"
#      set goals [lindex $hockeyplayer [expr $k + 2]]
#      putquick "notice $nick : $goals goals"
#      set assists [lindex $hockeyplayer [expr $k + 3]]
#      putquick "notice $nick : $assists assists"
#      set points [lindex $hockeyplayer [expr $k + 4]]
#      putquick "notice $nick : $points points"
#      lappend tempsortscore [$points $goals $assists $games $wosnick]
#}
#      set tempsortscore [lsort -decreasing $tempsortscore]
#      set sortscore ""
#     for {set i 0} {$i < 10} {incr i} {
#    set tiscore [lindex $tempsortscore $i]
#   if {$tiscore != ""} {
#      set newtempsortscore [string trimleft [lindex $tiscore 0] 0]
#      append sortscore [format "\0034 %s\.\003 %s\(%d\/%d\) " [expr {$i + 1}] [lindex $tiscore 2] $newtempsortscore [lindex $tiscore 1]]
#      }
#}
#	if {$sortscore == ""} {
#	putserv "PRIVMSG $channel :\002\003$statcol1\No one has scored yet!"
#return
#}
#set slength [llength $sortscore]
#putserv "PRIVMSG $channel :The top 10 Hockey Players"
#putserv "PRIVMSG $channel :$sortscore"
#}
############   end of standings procedure


################ timer procedure
proc hockeythrottled {id time} {
   global hockeythrottled nick channel
   if {[info exists hockeythrottled($id)]} {
      set left 0
      foreach t [utimers] {
         if {[string equal $hockeythrottled($id) [lindex $t 2]]} {
            set left [lindex $t 0]
            break
         }
      }
      putserv "NOTICE $nick :You have $left seconds left before your next jump attempt!"
      return 1
   } {
      set hockeythrottled($id) [utimer $time [list unset hockeythrottled($id)]]
      return 0
   }
}
################ end of timer procedure

###  this updates the log when eggdrop is loaded
putlog "\002\'Olympic Hockey'\002 Version $hockeyversion ©Rilly 2010 loaded"

Last edited by MIODude on Fri Feb 26, 2010 4:10 pm, edited 1 time in total.
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

Although it may conflict with the way in which your script is written thus far, I would probably hold the scores in an array variable. The array element name would be a nick and the corresponding array element value would be a tcl list of {games goals assists points}.

I would code self sufficient routines to read a file once whenever the bot is started/restarted using an EVNT bind of type init-server and write to the file whenever the array variable is written to using a trace command.

The remainder of your code would simply deal with the array variable and not the contents of the file directly.

Code: Select all

bind EVNT - init-server pGameDataRead

proc pGameDataWrite {args} {
    global vGameData
    set id [open game.txt w]
    if {[array size vGameData] != 0} {
        foreach {name value} [array get vGameData] {
            puts $id "$name [join $value]"
        }
    }
    close $id
    return 0
}

proc pGameDataRead {type} {
    global vGameData
    if {[file exists game.txt]} {
        set id [open game.txt r]
        set data [split [read -nonewline $id] \n]
        close $id
        foreach record $data {
            set vGameData([lindex [split $record] 0]) [lrange [split $record] 1 end]
        }
    }
    trace add variable vGameData write pGameDataWrite
    trace add variable vGameData unset pGameDataWrite
    return 0
}
I have done a limited amount of testing on the code and it seems to work fine.

Things to watch out for :-

Each array element value is a LIST and not a normal string. Additional code should take account of this.

Each array element value should be the same list length to make the remainder of your code simple. For example, if a nick has played two games but not registered any goals, assists or points, then the array element value should be {2 0 0 0}. NOT {2} and probably NOT {2 "" "" ""} as things stand.

If the file does not initially exist or is empty, then the array variable will not exist. Your code may need to take account of this.

*** EDIT *** I later put the trace commands for 'write' and 'unset' options on different lines since I can't seem to find the correct syntax for including both options on the same line (if this is possible). If array commands are used to set/modify data then a further trace line with 'array' option would most likely be required. Probably best to adhere to set vGameData($nick) whatever and unset vGameData($nick) which would not require further modification to the trace commands.
I must have had nothing to do
M
MIODude
Voice
Posts: 32
Joined: Mon Oct 09, 2006 6:26 pm

Post by MIODude »

Thanks for the reply arfer - i'll have a look at this and give it a try.. (sorry slow response after your post.. been a hectic work week...)
M
MIODude
Voice
Posts: 32
Joined: Mon Oct 09, 2006 6:26 pm

Post by MIODude »

This is just over my head.. i can't even begin to figure out what i need to write for the code. :(
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

Sorry I seem to have added to your confusion.

My idea was to provide independent code that takes care of reading from game.txt (after a bot start/restart) and writing to game.txt (after a change to the array variable vGameData).

Thereafter, your code would simply deal with the variable vGameData in memory and you need not further concern yourself with reading/writing directly from/to the file.

If the confusion lies with array variables, then I can only advise that they offer an ideal way to deal with multiple values within the same array variable name. Even then, I could easily be accused of understating their value since array commands offer ways, for example, of iterating through all or some of the array elements.

An array has a single variable name. It has elements which, if you like, are also names (sometimes called keys or indices). Each array element has an associated value. In our case the array name is vGameData. Each element name is the player or nick. Each element value is a tcl list of games, goals, assists and points for that player/nick.

Examples :-

the value for the player 'arfer' may be set using :-

Code: Select all

set vGameData(arfer) [list 1 0 2 0]
the player 'arfer' may be removed from the file completely using

Code: Select all

unset vGameData(arfer)
one can be added to the player 'arfer' games using :-

Code: Select all

set games [lindex $vGameData(arfer) 0]
set goals [lindex $vGameData(arfer) 1]
set assists [lindex $vGameData(arfer) 2]
set points [lindex $vGameData(arfer) 3]
set vGameData(arfer) [list [incr $games] $goals $assists $points]
Just to reiterate, the use of set or unset as in the examples above would automatically write to the file game.txt because of the code I provided.

The code below is an improvement in the code I already posted in that you can simply call the proc pGameAddValue together with the arguments player name, type to add to (games, goals, assists or points) and the number to add.

Code: Select all

bind EVNT - init-server pGameDataRead

proc pGameDataWrite {args} {
    global vGameData
    set id [open game.txt w]
    if {[array size vGameData] != 0} {
        foreach {name value} [array get vGameData] {
            puts $id "$name [join $value]"
        }
    }
    close $id
    return 0
}

proc pGameDataRead {type} {
    global vGameData
    if {[file exists game.txt]} {
        set id [open game.txt r]
        set data [split [read -nonewline $id] \n]
        close $id
        foreach record $data {
            set vGameData([lindex [split $record] 0]) [lrange [split $record] 1 end]
        }
    }
    trace add variable vGameData write pGameDataWrite
    trace add variable vGameData unset pGameDataWrite
    return 0
}

proc pGameAddValue {player type number} {
    global vGameData
    if {[info exists vGameData($player)]} {
        set games [lindex $vGameData($player) 0]
        set goals [lindex $vGameData($player) 1]
        set assists [lindex $vGameData($player) 2]
        set points [lindex $vGameData($player) 3]
    } else {
        set games [set goals [set assists [set points 0]]]
    }
    switch -- $type {
        games {incr games $number}
        goals {incr goals $number}
        assists {incr assists $number}
        points {incr points $number}
        default {}
    }
    set vGameData($player) [list $games $goals $assists $points]
    return 0
}
For example to add 1 to the player 'arfer' goals plus 2 to the player 'arfer' points :-

Code: Select all

pGameAddValue arfer goals 1
pGameAddValue arfer points 2
I must have had nothing to do
M
MIODude
Voice
Posts: 32
Joined: Mon Oct 09, 2006 6:26 pm

Post by MIODude »

Thank you very much for explaining how it all works and even putting it together for me! Its working great
Post Reply