Programmeerwedstrijd: Koehandel
Na enige tijd stilte is het wel weer eens tijd geworden voor een nieuwe programmeer wedstrijd op GoT!In de zoektocht naar een spelletje dat niet zomaar te brute-forcen is ben ik uitgekomen bij 'koehandel'.
Voor wie niet bekend is met het spel, het is zaak om kwartetten bij elkaar te handelen door deze te kopen in een veiling of door met andere spelers in onderhandeling te gaan. Aan het eind worden zowel de punten op de kwartetten als hun waarde meegeteld. Wie de hoogste score heeft is de winnaar. Het geld dat gebruikt wordt tijdens het handelen heeft bij afloop geen waarde meer!
Een van de aardige aspecten van het spel is de mogelijkheid te bluffen, dit levert ook voor computerspelers leuke optimalisatiemogelijkheden op, maar indien je betrapt wordt, krijgt iedereen inzage in je financiën!
Spelregels
Voor de standaard regels van koehandel, zie wikipediaLet op!
De spelregels voor deze contest wijken op details af van het standaard spel.
• bieden tijdens een veiling gebeurt sequentieel
• de 'geldezel' wordt vertegenwoordigd door handelswaar 'G'
• als de handelswaar op is en er alleen nog gehandeld kan worden, leidt een verkeerde handel initiëren tot het niet meer mogen starten van handel!
communicatie
Voor de communicatie en de scheidsrechter functie heb ik een server gemaakt, waarbij ik flink naar de rummikub opzet van Soultaker uit het programmeervuur heb gekeken.Ook nu zal de communicatie via HTTP GET messages gaan plaatsvinden, de mogelijke communicatie velden zijn als volgt:
market
het unieke id van de markt waarin de speler zich bevindt, dit wordt altijd meegestuurd en is handig indien een speler in meerdere spellen actief is. Dit hoeft niet gezet te worden door de speler en is altijd een getal groter dan 0.id
Het unieke id van de speler, dit wordt altijd meegestuurd en is handig indien een speler meerdere keren in een spel (als je tegen jezelf oefent) of in meerdere spellen actief is. Dit hoeft niet gezet te worden door de speler en is altijd een getal groter dan 0.type
Het type communicatie dat gaande is.Deze waarde gebruik je om te bekijken welke actie de server voor ogen heeft. De volgende waarden zijn mogelijk:
type=start
Deze wordt verzonden als een nieuwe beurt begint. Als je deze type ontvangt, mag je kiezen of je gaat onderhandelen (trade) met een specifieke speler, of dat je een veiling start (auction).
Indien je wilt gaan onderhandelen, zul je in je reply moeten aangeven met wie je wilt onderhandelen (W, N of E), over welke goederen (A t.m. J) en wat je openingsbod is (combinatie van biljetten).
Indien je een fout maakt in een van deze gegevens of als je te lang tijd neemt om te antwoorden, zal het spel automatisch omgezet worden in een veiling.
Fouten zijn onder andere het opgeven van een ongeldige tegenstander, ongeldige goederen of een ongeldig bod. Ook een tegenstander selecteren die de goederen niet heeft, of geld bieden wat je niet bezit, wordt gezien als een fout.
In principe is de auction de default actie wanneer je niks teruggeeft, dus is antwoorden niet strikt noodzakelijk. Let wel op, als alle handelswaar verhandeld is, is het alleen nog mogelijk te handelen! Als je nu geen geldige trade opzet, dan kun je geen handel meer starten en ben je overgeleverd aan je medespelers!
type=trade
Als je dit type ontvangt, dan ben je door een medespeler uitgedaagd tot een handel. Wie je tegenspeler is kun je zien door naar opponent te kijken, welke handelswaar zie je aan goods, van zijn bod zie je hoeveel kaarten je tegenspeler geboden heeft. Had je tegenspeler een bod gedaan van "nttf" (70) dan zie jij "QQQQ". Je kan ervoor kiezen om geen tegenbod te doen, of je kan proberen meer te bieden dan je tegenstander. Indien je een ongeldig bod doet verlies je meteen de handel!
type=auction
Als je dit type ontvangt, dan heeft een van je medespelers een veiling gestart. Via auctioneer kom je erachter wie de veiling gestart heeft, aan opponent kun je zien wie het huidige hoogste bod heeft ( indien er nog geen bod uitgebracht is wijst opponent naar de auctioneer. De hoogte van het huidige bod lees je af uit money, en aan goods kun je zien waar op geboden wordt.
Als reactie hoef je slechts een bod uit te brengen door in money een waarde te zetten die groter is dan het huidige bod. Indien je dit niet doet wordt je actie automatisch als pass geïnterpreteerd en doe je niet meer mee voor deze veilingronde.
Als je echter zelf de auctioneer bent en je ontvangt dit type, dan is de veilingronde ten einde en mag je kiezen wat je met de handelswaar doet. Als auctioneer heb je altijd het overkooprecht, dat wil zeggen dat je voor het hoogste bod altijd zelf de handelswaar mag kopen. Als je dit overkooprecht uitoefent betaal je aan de hoogste bieder.
----
Als je zelf de bieding gestart bent dan hoef je niets te doen totdat de veilingronde klaar is en je de mogelijkheid krijgt om je overkooprecht uit te oefenen.
type=information
Dit is een type dat je alleen maar kan ontvangen en waarop ook geen antwoord mogelijk is. Dit type wordt gebruikt om informatie te geven over het spelverloop. Als opponent op 'N' staat, goods op 'A' en money op 'ttf', dan betekend dit dat de speler tegenover jou A heeft gekocht voor 70,-.
Er is een uitzondering hierop, namelijk, wanneer een speler gebluft heeft. Als een speler een bod heeft gedaan dat hij niet kan betalen, dan krijgen alle spelers te zien hoeveel geld de speler in de hand heeft. De informatie zou dan net als bovenstaande kunnen zijn, met uitzondering dat er in het message gedeelte "bluffed" staat.
type=collect
Ook dit type kun je alleen maar ontvangen en wordt gebruikt om duidelijk te maken dat de server heeft besloten dat er geld of goederen bij jou weggehaald moeten worden.
Als er money opgehaald wordt na een auction, dan kun je nog aangeven hoe dit opgehaald moet worden, zo kun je de waarde 50 betalen met 1xf, of 5xt. Indien je niks aangeeft maakt de server een inschatting en bericht je wat hij voor betaling heeft gedaan via type=information.
type=receive
Dit is ongeveer hetzelfde als het collect type, alleen wordt er nu aangeduid dat je geld of goederen ontvangt.
type=end
Als je deze ontvangt is het spel ten einde, en kun je aan de message string zien wie er gewonnen heeft, als het goed is ben je al op de hoogte natuurlijk
De message string is samengesteld met de opponent en zijn score. bijvoorbeeld:
'W750N2020E=500'
om aan te geven dat speler 'W' 750 punten heeft, 'N' 2020 en 'E' 500.
opponent
Dit veld wordt gebruikt om aan te geven wie de tegenspeler is, mogelijke waarden zijn W, N, E, respectievelijk West, North, East. Als speler zit je altijd op de zuidelijke positie (S). Als je een tegenstander uitkiest zul je dus ook een van deze waardes moeten kiezen.Tijdens een auction verwijst opponent naar de speler die als niets wijzigt het handelswaar ontvangt. Dit begint met de auctioneer, dan de speler met het hoogste bod en uiteindelijk met de speler die met het handelswaar ontvangt.
auctioneer
Dit veld is in principe gelijk aan het opponent veld, alleen wordt het nu gebruilkt om de veilingmeester te duiden. Deze waarde hoef je dan ook nooit zelf te zetten.goods
De goederen waarover gehandeld wordt. Er zijn tien verschillende goederen:Naam | Waarde |
---|---|
A | 10 |
B | 40 |
C | 90 |
D | 160 |
E | 250 |
F | 350 |
G | 500 |
H | 650 |
I | 800 |
J | 1000 |
Als je bijvoorbeeld wil onderhandelen over item 'A', dan gebruik je 'goods=A'
Daarnaast kan er nog een min '-' teken voorstaan, dit heeft alleen betekenis als het type information is. Als deze min ervoor staat, betekent dit dat de betreffende speler deze hoeveelheid heeft moeten afstaan.
Voorbeelden:
type | goods | toelichting |
---|---|---|
auction | A-J | Good die wordt aangeboden. |
trade | A(A)-J(J) | Goods die worden verhandeld. Als opponent en jij er 2 van bezitten, zullen uiteindelijk toch 2 worden overgedragen. Altijd in combinatie van money en opponent |
collect | A(A)-J(J) | Goods die worden afgenomen om te worden overgedragen aan opponent. |
receive (na auction) | A-J | Goods die worden ontvangen. |
receive (na trade) | A(A)-J(J) | Goods die worden ontvangen. Opponent is gegeven. |
information (na auction) | A(A)-J(J) | Goods die worden ontvangen, in combinatie met betaald geld (-0/-QQ20). |
information (na trade) | A(A)-J(J) | Goods die worden ontvangen, in combinatie met betaald geld (-QQ). |
information | -A(A)-J(J) | Goods die worden afgegeven, in combinatie met ontvangen geld (QQ) van opponent. |
money
Via dit veld wordt de hoogte van een bod gecommuniceerd, mogelijke eenheden zijnmoney | waarde | initieel | via geldezel |
---|---|---|---|
n | 0 | 2 | - |
t | 10 | 4 | - |
f | 50 | 1 | 1 |
h | 100 | - | 1 |
T | 200 | - | 1 |
F | 500 | - | 1 |
Q | |
Elke combinatie hiervan is mogelijk. Dit geldt voor zowel ontvangen als verzenden.
Daarnaast kan er nog een min '-' teken voorstaan, dit heeft alleen betekenis als het type information is. Als deze min ervoor staat, betekent dit dat de betreffende speler deze hoeveelheid heeft moeten afstaan. Daarnaast kan er ook de letter 'Q' in voorkomen. Elke letter staat gelijk aan een item, maar de exacte waarde hiervan is onbekend. In geval van een auction staat de waarde er als nummer achter, bijvoorbeeld "money=QQ60". Dit kan betekenen dat er "tf" gebruikt is om te betalen, maar het zou ook "ff" kunnen zijn, indien de speler niet anders kon betalen.
Voorbeelden:
type | money | toelichting |
---|---|---|
auction | FThft | Hoogste bod tot nu toe. Dit hoeft niet over een te komen met werkelijke kaarten. Bijvoorbeeld FFFFF wordt betaald met FFFFTTh, want 5xF zit niet in het spel. |
trade | Aantal kaarten dat door tegenstander wordt geboden. Goods en opponent zijn gegeven. | |
collect (na trade) | FThftn | Eerder bod dient betaald te worden. Geen response nodig. |
collect (na auction) | FThft | Eerder bod dient betaald te worden. Response in de kaartjes om minimaal het bedrag te voldoen. Zonder response incasseert de server. |
receive | FThftn | Geld dat wordt ontvangen. Opponent wordt meegegeven, tenzij geld van de geldezel wordt ontvangen. |
information | FThf | Geld dat gegeven opponent ontvangt van geldezel. |
information | QQ20 | Geld dat opponent ontvangt na auction. |
information | -QQ20 | Geld dat opponent betaalt voor aangegeven goods na auction. Kan ook -0 zijn als niemand bood en kaartje gratis wordt ontvangen. |
information | Geld dat opponent ontvangt na trade. Voor de verloren goods staat een - (min). | |
information | Geld dat opponent betaalt voor trade van de ontvangen goods. |
message
Ter informatie of bij een ongeldige actie, zal de server een information type teruggeven, met in de message een string die beschrijft wat er aan de hand is. Deze message bevat geen spaties, slechts underscores. Veel voorkomende messages zijn:type | message | toelichting |
---|---|---|
information | begin | Een nieuw spel begint. |
information | bluffed | Na een auction blijkt een andere speler niet de benodigde money in bezit te hebben. In opponent staat wie en in money staat zijn werkelijk bezit. |
information | second_bluff_not_allowed | Bij een auction mag je maar 1 keer betrapt worden op een bod wat je niet kunt betalen. De tweede keer vervalt je bod. |
information | no_opponement_specified | Je probeert een handel op te zetten en vergeet opponent=W|N|E mee te geven. |
information | opponent_goods_do_not_match | Je probeert een handel op te zetten zonder dat de opponent er minimaal 1 van bezit. |
information | goods_not_owned_by_player | Je probeert een handel op te zetten zonder er zelf minimaal 1 van te bezitten. |
information | invalid_bid | Je probeert een handel op te zetten met geld dat je niet bezit. |
auction | W10N20E30W40 | Biedgeschiedenis: spelers kunnen meerdere keren voorkomen. |
trade | equal_bid | Beide spelers boden hetzelfde. Je wordt gevraagd opnieuw een bod uit te brengen. |
end | SxWxNxEx | Eindscores |
Score
De puntentelling is simpel, als het spel klaar is, dan wordt het aantal kwartetten dat een speler heeft gebruikt om de waarde van zijn goederen (alleen de kwartetten) te vermenigvuldigen.Als een speler drie kwartetten heeft, bv. AAAA, BBBB en CCCC ( 10, 40, 90 ) dan is zijn score 3 * ( 10 + 40 + 90 ) = 420.
Een speler met maar één kwartet van FFFF ( 350 ) heeft een score van 1 * ( 350 ) = 350 en heeft dus verloren van de speler met drie lagere kwartetten.
Eventueel geld dat over is na de onderhandelingen telt niet mee voor de score!
Voorbeeld
Voor diegene die nu in hun hoofd tl;dr hebben knipperen, hier een voorbeeldronde.direction | goods | type | opponent | money | auctioneer | message | uitleg |
server -> S | start | server start ronde | |||||
S -> server | auction | speler kiest voor veiling | |||||
server -> W | F | auction | E | E | server vraagt W voor response | ||
W -> server | t | W bied 't' | |||||
server -> N | F | auction | E | t | N | E10 | server vraagt N voor response |
N -> server | N past | ||||||
server -> E | F | auction | N | t | W | N10E0 | server vraagt E voor response |
E -> server | tttt | E bied 'tttt' | |||||
server -> W | F | auction | N | tttt | E | W0N40 | server slaat S ( auctioneer ) over en vraagt W voor response |
W -> server | ntttt | W bied 'ntttt', hetgeen niet hoger is dan het vorige bod | |||||
server -> S | F | auction | E | tttt | W10N0E40W40 | server interpreteert response van W als pas en biedt auctioneer de koopwaar aan | |
S -> server | tttt | S heeft er 'tttt' voor over en oefent dus zijn kooprecht uit | |||||
server -> S | F | receive | server informeert S dat hij de koopwaar in ontvangst mag nemen | ||||
server -> S | collect | E | tttt | maar er moet wel nog betaald worden, 'tttt' om precies te zijn | |||
S -> server | tttt | S geeft aan dat hij met vier 'tien' kaarten wil betalen | |||||
server -> E | receive | W | tttt | server informeert E dat hij 'tttt' opgehaald heeft bij S en dat E deze nu mag hebben | |||
server -> W | F | information | E | -QQQQ40 | W wordt op de hoogte gebracht van de handel, er zijn vier kaarten verhandeld met een waarde van 40 | ||
server -> N | F | information | N | -QQQQ40 | idem voor N | ||
server -> W | information | N | QQQQ40 | Dan krijgt W te horen wie er geld ontvangen heeft | |||
server -> N | information | W | QQQQ40 | idem voor N |
direction | goods | type | opponent | money | auctioneer | message | uitleg |
server -> N | start | server start ronde | |||||
N -> server | H | trade | W | nntt | Speler geeft aan met speler 'W' te willen onderhandelen voor goederen H en wil daar 20 voor bieden | ||
server -> E | H | trade | E | QQQQ | server informeert W dat hij uitgedaagd wordt door E, die wil onderhandelen over H en er vier kaarten voor overheeft | ||
E -> server | ttff | speler EE biedt 120 terug | |||||
server -> E | information | invalid_bid | De server informeert E dat dit een ongeldig bod was ( in dit geval had de speler slechts de het startkapitaal ter beschikking ) | ||||
server -> E | H | collect | E | De server haalt nu de goederen op van E, aangezien deze met zijn verkeerde bod effectief gepast heeft. | |||
server -> N | H | receive | W | N wordt geïnformeerd dat hij goederen H ontvangt | |||
server -> N | collect | W | nntt | Daarnaast moet winnaar natuurlijk wel betalen | |||
server -> E | receive | E | nntt | server informeert E dat hij 20 heeft ontvangen van N (E ten opzichte hem) | |||
server -> S | H | information | N | -QQQQ | S krijgt informatie | ||
server -> W | H | information | W | -QQQQ | W krijgt informatie | ||
server -> S | -H | information | N | QQQQ | S krijgt informatie | ||
server -> W | -H | information | W | QQQQ | W krijgt informatie |
praktisch
Je hebt vijf seconden de tijd voor het opzetten van een connectie en het geven van een antwoord in de vorm van een plain text. Gebruik hiervoor het format van een GET-statement: ?var1=value1&var2=value2.Je mag met meerdere dezelfde spelers in één spel gaan zitten tijdens het testen/debuggen maar tijdens het eindtournooi zal dit natuurlijk niet plaatsvinden. Twee spelers met elkaar laten samenspelen zit er daarom niet in
Je kan een spel beginnen door de server een GET string te sturen die als volgt opgebouwd is:
?connect&url1=http://iets.nl&url2=etc...
Zo kunnen er tot maximaal vier verschillende urls meegegeven worden. ( mogen ook dezelfde zijn als je je speler tegen zichzelf wil laten spelen )
Daarnaast kun je ook via deze pagina een spel starten: http://www.houbenweb.nl/market.html
Deze maakt deze query voor je. Posities die niet ingevuld zijn worden door de server aangevuld met spelers die op alle response passen.
Voor de broodnodige debugging worden er logs aangemaakt voor alle spelers.
Deze zijn op te vragen met de volgende GET string:
?log=ID
waarbij ID het id is dat je bij het connecten ( en elke request van de server ) krijgt.
Als laatste de locatie van de server, deze vind je op http://houbenweb.nl:56789
Jullie krijgen ruim twee maanden de tijd om jezelf voor te bereiden op het eindtournooi, zodat we in de eerste week van het nieuwe jaar erachter komen wie de beste koehandelaar weet te programeren!
Ik wens jullie allemaal veel succes en hoop dat iedereen een poging waagt!
Voor dit topic is toestemming van de PRG crew
[ Voor 255% gewijzigd door Bolukan op 23-11-2010 12:33 ]
oprecht vertrouwen wordt nooit geschaad