High Scores for game - vb.net

I am trying to get a high scores including player name to display on a separate form after all lives are lost in a game. I currently have this code for the high scores form - however it is only displaying the one score in the array and I am wanting to store 10 scores and also player's names.
Imports System.IO
'Code allows the computer to read from the text file containing player scores.'
Public Class Form3
Dim highscore(9) As Integer ' array for highscores
Dim playername(9) As String
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim i, value1, value2 As Integer 'player score variables
Dim DataFile As StreamWriter
' Static save As String
value1 = lblScore.Text ' assigns the players score to value1
value2 = lblScore.Text ' assigns the players score to value2
i = 0
DataFile = New StreamWriter("D:\mmend12\My Documents\IPT\Projects\Brandon Moss - Major Project Assignment\Cosmic Crusade\Cosmic Crusade\bin\Debug\HighScore.txt")
i = 0
For i = 0 To 9
If highscore(i) < value1 Then 'checks to see if the players score is bigger than the score
value1 = highscore(i) ' assigns the value of highscore to value 1
highscore(i) = value2 'assigns the players score to the highscore
value2 = value1 ' assigns the previous highscore to value1
End If
lbxHighScores.Items.Add(highscore(i)) ' displays the scores
'lbxNames.Items.Add(playername(i))
DataFile.WriteLine(highscore(i)) ' saves the highscores to disk
' DataFile.WriteLine(playername(i))
Next
DataFile.Close()
End Sub
Private Sub btnShowScores_Click(sender As Object, e As EventArgs) Handles btnShowScores.Click
Dim DataFile As StreamReader
'Declares the variable name "DataFile" as an instance of StreamWriter, meaning that DataFile will behave like a StreamWriter object.'
'Dim J As Integer
DataFile = New StreamReader("D:\mmend12\My Documents\IPT\Projects\Brandon Moss - Major Project Assignment\Cosmic Crusade\Cosmic Crusade\bin\Debug\HighScore.txt")
'Using the file path/address written above, a test.txt file is added in this folder.'
'For J = 1 To 10
'Creates a fixed loop, that loops 10 times
For i = 0 To 9
highscore(i) = DataFile.ReadLine
lbxHighScores.Items.Add(DataFile.ReadLine)
Next
DataFile.Close()
'Closes the data file.
End Sub
I have this code in the game form after all lives are lost:
If PlayersLives = 0 Then
End If
PlayerName = InputBox("Enter your username ")
lblName.Text = PlayerName
Form3.lblScore.Text = lblScoreNumber.Text
Form3.lblPlayer.Text = lblName.Text
Can anyone provide assistance with this.

I would respectfully suggest rewriting the Form3 code as follows ..
I'm assuming that when you click on a name in the ListBox, the associated score is displayed in LblScore
Anyhow back to the code. This way, the code to save and load the scores is separated from your Load event and the code that modifies the list of high scores is also separated out. It will be easier to maintain/modify later. It's also better to manipulate data separately from controls to avoid the risk of inadvertent modification by users.
Each player and their score is now stored in instances of the class Playerand all the players are stored in a List (Of Player)called highScores
There is also now a sub called UpdateListBox which uses the highScores list as a data source. The items to display are the .Name property of each player and the value that is returned when you click on the name of a player is the score which is then assigned to lblScore without any need for looping through arrays or lists.
Public Class Form3
'Code allows the computer to read from the text file containing player scores.'
Friend Class Player
Public Property Score As Integer
Public Property Name As String
End Class
Dim highscores As New List(Of Player) ' array for highscores
Public Sub AddScoreIfHighEnough(player As String, score As Integer)
'make sure that the high score list is sorted first
highscores = highscores.OrderByDescending(Function(x) x.Score).ToList
'work down though the list
For Each plyr As Player In highscores
'if the score is higher than the current item in the list,
'insert the new score there and exit the loop
If score > plyr.Score Then
highscores.Insert(highscores.IndexOf(plyr), New Player With {.Name = player, .Score = score})
Exit For
End If
Next
highscores.Add(New Player With {.Name = player, .Score = score})
'if after the loop has completed, the number of items is
'greater than 10, remove the lowest
If highscores.Count > 10 Then
highscores.Remove(highscores.Last)
End If
UpdateListbox()
SaveScoreData()
End Sub
Private Sub SaveScoreData()
Using DataFile As New StreamWriter("D:\mmend12\My Documents\IPT\Projects\Brandon Moss - Major Project Assignment\Cosmic Crusade\Cosmic Crusade\bin\Debug\HighScore.txt")
For Each plyr As Player In highscores
DataFile.WriteLine(plyr.Name) ' saves the name to disk
DataFile.WriteLine(plyr.Score.ToString) 'saves the score
Next
End Using
End Sub
Private Sub LoadScoreData()
highscores.Clear()
Using DataFile As New StreamReader("D:\mmend12\My Documents\IPT\Projects\Brandon Moss - Major Project Assignment\Cosmic Crusade\Cosmic Crusade\bin\Debug\HighScore.txt")
While Not DataFile.EndOfStream
Dim tempPlayerScore As New Player With {
.Name = DataFile.ReadLine, ' saves the name to disk
.Score = CInt(DataFile.ReadLine) 'saves the score
}
highscores.Add(tempPlayerScore)
End While
End Using
UpdateListbox()
End Sub
Private Sub UpdateListbox()
lbxHighScores.Items.Clear()
For Each plyr As Player In highscores
lbxHighScores.Items.Add(plyr.Name & " " & plyr.Score)
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadScoreData()
End Sub
Private Sub LbxHighScores_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lbxHighScores.SelectedIndexChanged
If Not IsNothing(lbxHighScores.SelectedItem) Then
lblScore.Text = CType(lbxHighScores.SelectedItem, Player).Score.ToString
End If
End Sub
End Class
In your code to add a high score, use something like
If PlayersLives = 0 Then
End If
PlayerName = InputBox("Enter your username ")
lblName.Text = PlayerName
form3.AddScoreIfHighEnough(lblName.Text, CInt(lblScoreNumber.Text))
Form3.lblPlayer.Text = lblName.Text

Related

VB.net Placing a .txt file into a Class List and assigning a property to certain indexes of the .txt file

I have a problem, I've created a class list for my sort program, so I can sort the items based on names. I was able to do it with assigned data but I don't know how to add data to the class from a txt file, nor assigning properties to those items once the file is loaded.
My current code:
Public Class PatientSorter
Public Class Patients
Property Name As String
Property Age As Integer
Property Weight As Double
Property Height As Integer
Public Overrides Function ToString() As String
Return String.Format("{0}: {1} years old, {2} mm, {3} kg", Name, Age, Height, Weight)
End Function
End Class
Public Sub PatientSorter_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim i As Integer
Do While i <= DataEntry.lstPatientArray.Items.Count - 1
lstCurrentData.Items.Add(DataEntry.lstPatientArray.Items(i))
i = i + 1
Loop
End Sub
Private Sub btnSearchForm_Click(sender As Object, e As EventArgs) Handles btnSearchForm.Click
Me.Hide()
Search.Show()
End Sub
Public Sub BubbleSort(ByRef patients As List(Of Patients))
For i = 0 To patients.Count - 2
Dim doneSwap = False
For j = i + 1 To patients.Count - 1
If patients(i).Name > patients(j).Name Then
Dim tmp = patients(j)
patients(j) = patients(i)
patients(i) = tmp
doneSwap = True
End If
Next
If Not doneSwap Then Return
Next
End Sub
Public Sub btnNameSort_Click(sender As Object, e As EventArgs) Handles btnNameSort.Click
Dim fileReader As String
fileReader = My.Computer.FileSystem.ReadAllText("C:\Data.txt")
Dim patients As New List(Of Patients)
BubbleSort(patients)
End Sub
End Class
Some of the Data in the txt file, first line is name, second is age, third is height and fourth is weight:
Monty Reyes
28
1700
70.7
Kier Burke
45
1800
93.5
My goal is to sort the data from the txt file using my bubblesort based on names. Not really able to do that without the data. Hopefully someone out there can help me or give me a clue on something I'm missing.
Using ReadAllLines instead of ReadAllText will give you an array of all line items in the file. You can then loop through that array an extract the data line by line to create and populate your Patient objects, which you'd then insert into your list.
Dim patients As New List(Of Patient)
Dim data = System.IO.File.ReadAllLines("C:\Data.txt") 'read lines into an array
'loop through the array, incrementing the index by 4 each iteration
For index = 0 To data.Length - 1 Step 4
Dim patient = New Patient() 'create a Patient
'Populate the patient data by accessing the current 4 array indexes
patient.Name = data(index)
patient.Age = data(index + 1)
patient.Weight = data(index + 2)
patient.Height = data(index + 3)
patients.Add(patient) 'add the Patient to the list of Patients
Next

Display line says index was out of range

There is a button that displays an item from an array by searching an input in another array. In this instance, I want to display an item from animalArray.
To do this, a user needs to input a certain name from the nameArray. Binary search, will compare the input and nameArray(middle). But when all that is done, when displaying the array using listbox it crashes and says "index was out of bounds of the array". Even though all items in all arrays has 9 items including 0.
binarySearch(nameArray, animalArray, InputBox("Enter Owner name", "Owner name"))
How to solve this?
Sub binarySearch(ByVal array1, ByVal array2, ByVal item)
Sort()
Dim low = 0
Dim high = 9
Dim middle As String
Dim subfindindex = -1
Do While low <= high And subfindindex = -1
middle = (low + high) \ 2
If array1(middle) = item Then
subfindindex = middle
Exit Do
End If
If middle > item Then
high = middle - 1
Else
low = middle + 1
End If
Loop
ListBox1.Items.Add(array2(subfindindex)) '<--- index was out of bounds of array
End Sub
Your main problem is that you're comparing a number to a name, and attempting to determine which is greater:
If middle > item Then
Instead, you'll want to compare the number (the value of the middle variable) to the index of the name in the name array.
That said, you'll get more mileage with this by using lists instead of arrays, and by descriptively naming and strongly typing your parameter variables. Here's the working code:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Animals As New List(Of String)
Dim Names As New List(Of String)
Animals.Add("Dog")
Animals.Add("Cat")
Animals.Add("Sheep")
Animals.Add("Goat")
Animals.Add("Chicken")
Animals.Add("Fish")
Animals.Add("Cow")
Animals.Add("Snake")
Animals.Add("Rabbit")
Animals.Add("Squirrel")
Names.Add("Jim")
Names.Add("Betty")
Names.Add("Frank")
Names.Add("Paul")
Names.Add("Susan")
Names.Add("Debbie")
Names.Add("Bob")
Names.Add("Tina")
Names.Add("Fred")
Names.Add("Bill")
Me.BinarySearch(Names, Animals, InputBox("Enter Owner name", "Owner name"))
End Sub
Sub BinarySearch(Names As List(Of String), Animals As List(Of String), Name As String)
Dim SubFindIndex As Integer
Dim Middle As Integer
Dim High As Integer
Dim Low As Integer
SubFindIndex = -1
High = 9
Low = 0
Do While Low <= High And SubFindIndex = -1
Middle = (Low + High) \ 2
If Names(Middle) = Name Then
SubFindIndex = Middle
Exit Do
End If
If Middle > Names.IndexOf(Name) Then
High = Middle - 1
Else
Low = Middle + 1
End If
Loop
Me.ListBox1.Items.Add(Animals(SubFindIndex))
End Sub
End Class
But there's a lot simpler way of accomplishing the same goal:
Sub BinarySearch2(Names As List(Of String), Animals As List(Of String), Name As String)
Dim Animal As String
Dim Index As Integer
Index = Names.IndexOf(Name)
Animal = Animals(Index)
Me.ListBox1.Items.Add(Animal)
End Sub
--EDIT--
Here's what you should see after entering a name from the list in the InputBox:

Access a panel from another form with increment variable name

Public Sub StatusLoad(ByVal id As String)
''Dim F As New Apps
''Dim W As Panel = DirectCast(F.Controls(id), Panel)
Dim count As Long = 0
Dim strQueryStat As String = "SELECT * FROM sample_db.ronda WHERE id = '" + id + "'"
Dim SqlCmdStat As New MySqlCommand(strQueryStat, dbCon)
Reader = SqlCmdStat.ExecuteReader
While Reader.Read
count = count + 1
MsgBox("id" & count)
Dim status_db = Reader.GetString("status")
If status_db = 0 Then
Apps.id.BackColor = Color.Green '<------
MsgBox("Green")
Else
Apps.BackColor = Color.Red
MsgBox("Red")
End If
End While
End Sub
I want to use 'id' variable that get from other form to find the panel name from the other form. the above code is in a class. the panel that i want to access is at another form.
at the other for i send "con.StatusLoad(id)". the name of panel is id1 , id2 , id3 ...... the error is at the arrow
Private Sub app_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
con.ManageConnection(False)
For index As Integer = 1 To 2
Dim id As String = "id" & index
con.StatusLoad(id)
Next index
End Sub
Each control, including forms, has a Controls property that contains a collection of child controls. You can index that collection by ordinal or name, e.g.
For i = 1 To 5
Dim pnl = Me.Controls("Panel" & i)
'...
Next
Note that you'll be getting a Control reference back, so you can only use it to access members of the Control class. If you want to access members of a specific type of control then you must cast as that type.
Controls is a public member so it can be accessed from outside the form but probably shouldn't be. The same "rules" apply as would always apply to making changes to controls on a form, i.e. best practice dictates that it's done inside that form only.

Binary Search or Insertion Sort with list view [Visual Basic .net]

Recently when creating a program for my client as part of my computing project in visual basic .net I've came across a problem, which looks like following; In order to receive additional marks for my program I must take an advantage of either Binary Search or Insertion Sort subroutine declared recursively, so far the only place I can use it on is my View form which displays all reports generated by program but the problem with this is since I'm using MS Access to store my data all of the data is downloaded and placed in listview in load part of form. So the only way I can use it is by running it on listview which is a major problem for me due to the fact that I'm not very experienced in vb.
For binary search I have tried downloading all of the items in specified by user column into an array but that's the bit I was struggling on the most because I'm unable to download all items from only one column into an array. Also instead of searching every single column user specifies in my form in which column item is located (For example "19/02/2013" In Column "Date"), In my opinion if I manage to download every single entry in specified column into an array it should allow me to run binary search later on therefore completing the algorithm. Here's what I've got so far.
Sub BinarySearch(ByVal Key As String, ByVal lowindex As String, ByVal highindex As String, ByVal temp() As String)
Dim midpoint As Integer
If lowindex > highindex Then
MsgBox("Search Failed")
Else
midpoint = (highindex + lowindex) / 2
If temp(midpoint) = Key Then
MsgBox("found at location " & midpoint)
ElseIf Key < temp(midpoint) Then
Call BinarySearch(Key, lowindex, midpoint, temp)
ElseIf Key > temp(midpoint) Then
Call BinarySearch(Key, midpoint, highindex, temp)
End If
End If
End Sub
Private Sub btnSearch_Click(sender As System.Object, e As System.EventArgs) Handles btnSearch.Click
Dim Key As String = txtSearch.Text
Dim TargetColumn As String = Me.lstOutput.Columns(cmbColumns.Text).Index
Dim lowindex As Integer = 0
Dim highindex As Integer = lstOutput.Items.Count - 1
'Somehow all of the items in Target column must be placed in temp array
Dim temp(Me.lstOutput.Items.Count - 1) As String
' BinarySearch(Key, lowindex, highindex, temp)
End Sub
For Insertion sort i don't even have a clue how to start, and the thing is that I have to use my own subroutine instead of calling system libraries which will do it for me.
Code which I have to use looks like following:
Private Sub InsertionSort()
Dim First As Integer = 1
Dim Last As Integer = Me.lstOutput.
Dim CurrentPtr, CurrentValue, Ptr As Integer
For CurrentPtr = First + 1 To Last
CurrentValue = A(CurrentPtr)
Ptr = CurrentPtr - 1
While A(Ptr) > CurrentValue And Ptr > 0
A(Ptr + 1) = A(Ptr)
Ptr -= 1
End While
A(Ptr + 1) = CurrentValue
Next
Timer1.Enabled = False
lblTime.Text = tick.ToString
End Sub
Any ideas on how to implement this code will be very appreciated, and please keep in my mind that I'm not very experienced in this language
Perhaps this might give you a place to begin. If you already have a ListView with "stuff" in it you could add a button to the form with the following code to copy the Text property for each item into an array:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim myArray(Me.ListView1.Items.Count - 1) As String
Dim i As Integer
' load array
For i = 0 To Me.ListView1.Items.Count - 1
myArray(i) = Me.ListView1.Items(i).Text
Next
' show the results
Dim s As String = ""
For i = 0 To UBound(myArray)
s &= String.Format("myArray({0}): {1}", i, myArray(i)) & vbCrLf
Next
MsgBox(s, MsgBoxStyle.Information, "myArray Contents")
' now go ahead and manipulate the array as needed
' ...
End Sub

Public subs don't work in this scenario

I have a form named FrmDrvouchers. It contains some public subprocedures.
I call these subs from another form which opens from a form which is opened from FrmDrVouchers as a dialog.
When I open FrmDrvouchers directly, everything works. But when I call FrmDrvouchers from another project which is also part of this solution, its public subs don't work when I call them from another (dialog) form.
Here is the code of the Button Click from which I open FrmDrvouchers:
Dim FrmDrv As FrmDrVouchers = New FrmDrVouchers()
FrmDrv.Show()
This works, but those public subs don't. Why?
Thanks For ur response,
It just skip what i want to do, but not throws any Exceptions,
Now I m posting my Code,,, plz have a look on that,,
Here is my Main form's MenuStrip Button Click code :
Private Sub CashPaymentToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CashPaymentToolStripMenuItem.Click
Dim DrVouchers As Transactions.FrmDebitVouchers = Transactions.New FrmDebitVouchers()
DrVouchers.Show()
End Sub
Here is the FrmDebitVouchers's Public Subs which are not working,,, in the sense that they skip the function which i have written but not throwing any Exception,,
Public Sub DrVoucherOPen(ByVal VoucherNo As Integer)
'Filling the Dataset with selected Voucher No to OPen the record
DebitVouchersTableAdapter.FillByVoucher(Flr12131DataSet.DebitVouchers, VoucherNo)
VoucherDateDateTimePicker.Enabled = False
End Sub
Public Sub DrVoucherBodyOPen(ByVal VoucherNo As Integer)
'---------Procedure to Open DrVouchersBody And to OPen it in Datagridview-------------'
'Getting the User No, and if it is admin then load fill dataset and allow user to edit the record
If GetUserNumber() = 1 Then
'Filling the dataset
DebitVouchersBodyTableAdapter.FillByVoucher(Flr12131DataSet.DebitVouchersBody, VoucherNo)
DrBodyDGV.DataSource = Nothing
Dim Sum As New Decimal
'Initializing the SerialNumbers variable
SerialNumbers = New List(Of Integer)
'Setting datagridview to opend record
For i = 0 To Flr12131DataSet.DebitVouchersBody.Rows.Count - 1
DrBodyDGV.Rows.Add()
DrBodyDGV.Rows(i).Cells(0).Value = Flr12131DataSet.DebitVouchersBody.Rows(i).Item("SerialNo")
DrBodyDGV.Rows(i).Cells(3).Value = Flr12131DataSet.DebitVouchersBody.Rows(i).Item("AccountNo")
DrBodyDGV.Rows(i).Cells(6).Value = Flr12131DataSet.DebitVouchersBody.Rows(i).Item("Debit")
DrBodyDGV.Rows(i).Cells(7).Value = Flr12131DataSet.DebitVouchersBody.Rows(i).Item("Narration")
'Getting serial No into List
SerialNumbers.Add(Flr12131DataSet.DebitVouchersBody.Rows(i).Item("SerialNo"))
'Getting Account Name into Datagridview
If Not Not IsNumeric(DrBodyDGV.Rows(i).Cells(3).Value) Then
Dim Qa As New Flr12131DataSetTableAdapters.QueriesTableAdapter
Dim StrAccountName = Qa.GetAccountName(DrBodyDGV.Rows(i).Cells(3).Value)
DrBodyDGV.Rows(i).Cells(5).Value = StrAccountName
Else
End If
Sum += DrBodyDGV.Rows(i).Cells(6).Value
Next
TxtTotal.Text = Sum
'Setting the controls properties for admin
DrBodyDGV.AllowUserToAddRows = True
DrBodyDGV.AllowUserToDeleteRows = True
DrBodyDGV.ReadOnly = False
BtnSave.Enabled = True
BtnDelete.Enabled = True
BtnPrint.Enabled = True
ToUpdate = True
Else
'If user is not admin then load all record and not allow user to modify it or delete
' Bounding the datagridview
Dim Sum As Decimal = 0
BtnSave.Enabled = False
DebitVouchersBodyTableAdapter.FillByVoucher(Flr12131DataSet.DebitVouchersBody, VoucherNo)
DrBodyDGV.DataSource = Flr12131DataSet.DebitVouchersBody
For i = 0 To DrBodyDGV.Rows.Count - 1
If Not Not IsNumeric(DrBodyDGV.Rows(i).Cells(3).Value) Then
Dim Qa As New Flr12131DataSetTableAdapters.QueriesTableAdapter
Dim StrAccountName = Qa.GetAccountName(DrBodyDGV.Rows(i).Cells(3).Value)
DrBodyDGV.Rows(i).Cells(5).Value = StrAccountName
Else
End If
Sum += DrBodyDGV.Rows(i).Cells(6).Value
Next
TxtTotal.Text = Sum
DrBodyDGV.AllowUserToAddRows = False
DrBodyDGV.AllowUserToDeleteRows = False
' DrBodyDGV.edit()
DrBodyDGV.ReadOnly = True
BtnSave.Enabled = False
BtnDelete.Enabled = False
BtnPrint.Enabled = True
End If
End Sub
Here is another the DrVouchersRecord form from which I call Public Subs:
Private Sub DrVouchersRecordDataGridView_CellDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DrVouchersRecordDataGridView.CellDoubleClick
Dim FrmDrVouchers As FrmDebitVouchers = New FrmDebitVouchers()
If FrmDrVouchers.DrBodyDGV.Rows.Count > 1 Then
Dim Ans As Integer
Ans = MsgBox("Unsaved changes will be lost, want to proceed", vbYesNo + vbInformation, "Alert")
If Ans = vbYes Then
Dim VoucherNo As New Integer
VoucherNo = DrVouchersRecordDataGridView.CurrentRow.Cells(0).Value
FrmDrVouchers.DrVoucherOPen(VoucherNo)
FrmDrVouchers.DrVoucherBodyOPen(VoucherNo)
Me.Close()
End If
Else
Dim VoucherNo As New Integer
VoucherNo = DrVouchersRecordDataGridView.CurrentRow.Cells(0).Value
FrmDrVouchers.DrVoucherOPen(VoucherNo)
FrmDrVouchers.DrVoucherBodyOPen(VoucherNo)
Me.Close()
End If
End Sub
My forms sequence is:
FrmMain is my main startUp form
After that FrmDebitVouchers Open on menustripButtonclick
After that DebitVouchersRecord is Open as Dialog from DrmDebitVouchers,,, and from these Public Subs are called
I Have added Refrence also
Waiting for ur answers,
This problem has hit many programmers coming from VB6 to VB.NET.
In your DataGridView_DoubleCellClick event you create a NEW instance of FrmDebitVouchers.
Then your code refers to property/methods/objects of this new INSTANCE, not of the original one created via CashPaymentToolStripMenuItem_Click. (Also note that this new instance is never showed on the screen, so you are sending/requesting changes to an hidden form instance)
Of course, the DrBodyDGV.Rows.Count is zero on this INSTANCE (referenced as FrmDrVouchers) because probably this INSTANCE has never been intialized like the first one.
Try to add a FrmDrVouchers.Show() after the creation and you will see the hidden SECOND INSTANCE of the form class FrmDebitVouchers.
To solve your problem, you need to pass the reference of the first FrmDebitVouchers instance to the DrVouchersRecord form (for example in the constructor or via a public property) and then use that reference instead of creating FrmDrVouchers