Open Side Menu Go to the Top
Register
Computers Conquer Texas Hold'em Poker for First Time Computers Conquer Texas Hold'em Poker for First Time

01-10-2015 , 10:48 PM
Quote:
Originally Posted by David Sklansky
Make the river bet 3 BB instead of 2 and they have to deal another 20 trillion hands.
Hmm, I don't understand why does changing river sizing would make the game tree any bigger, hence harder to calculate? Every street would still be capped at 4 bets and both players start with 8 small bets to cover pre+flop, 4 turn bets and 4 river bets = 24 small bets total. (Normal HU LHE game has 12 small bet cap.)

Or did you mean that players can opt to bet 2 or 3 on the river? However I don't know how that would work in general? Can you raise 2-lead on river with 3?

EDIT: Just remembered this topic: http://forumserver.twoplustwo.com/10...enario-869820/
Sounds like 20 trillion isn't really even a big increase fraction-wise to the original number?

Quote:
Put a preflop flop out where those five cards are dead and they have to deal more than 50 quintillion.
Rephrase please? Didn't quite catch your drift.

Last edited by ezdonkey; 01-10-2015 at 11:01 PM.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-10-2015 , 11:01 PM
I believe he means that if five cards were burned face up before the game then the game would have to be recomputed and the size would explode.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-10-2015 , 11:07 PM
Quote:
Originally Posted by TheBryce2
I believe he means that if five cards were burned face up before the game then the game would have to be recomputed and the size would explode.
That actually sounds like a pretty cool game. I think even 3 would be good for starters. Dead Flop Hold'em.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-10-2015 , 11:18 PM
Quote:
Originally Posted by ezdonkey
Hmm, I don't understand why does changing river sizing would make the game tree any bigger, hence harder to calculate? Every street would still be capped at 4 bets and both players start with 8 small bets to cover pre+flop, 4 turn bets and 4 river bets = 24 small bets total. (Normal HU LHE game has 12 small bet cap.)

Or did you mean that players can opt to bet 2 or 3 on the river? However I don't know how that would work in general? Can you raise 2-lead on river with 3?

EDIT: Just remembered this topic: http://forumserver.twoplustwo.com/10...enario-869820/
Sounds like 20 trillion isn't really even a big increase fraction-wise to the original number?


Rephrase please? Didn't quite catch your drift.
They have to start from scratch with different limits.

With a preflop flop they have 2.6 million strategies to figure out.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-10-2015 , 11:25 PM
Quote:
Originally Posted by David Sklansky
They have to start from scratch with different limits.

With a preflop flop they have 2.6 million strategies to figure out.
So how many decision points? I think someone mentioned 400 quads, so a factor of 1000 increase? Doesn't seem too far fetched with improved hardware and perhaps some tweaking of the algorithm. They would be finished before you could get a decent amount of people to start playing the game.

I think if you're going down this route, you should find a game that's definitely out of reach.

Even then the cat's out of the bag: the best way to compete against the most skilled players HU is by building smart AI and copying its strategy as much as possible.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-10-2015 , 11:44 PM
Quote:
Originally Posted by ezdonkey
So I'm basically querying a supercomputer, no? A one which regular people don't have access to? Could someone grab the source codes and be able to build a similar system which can query the database almost real-time with a moderate investment? (Moderate in this case something in the range of 10-50k?)
Nah, no supercomputer for the query tool. It's running on a more-or-less standard desktop PC stuffed with a few extra drives. It's generating the strategy that takes a lot of computing resources - that wouldn't be a modest investment. The query tool is slow mostly because the strategy is compressed, and it has to read a fairly big chunk off disk to answer anything.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-10-2015 , 11:58 PM
Here is a some code from a file cepheus.js I haven't really read through it
Spoiler:

Code:
window.cepheus = {

	heartsSelect: $('#hearts-select.card'),
	clubsSelect: $('#clubs-select.card'),
	spadesSelect: $('#spades-select.card'),
	diamondsSelect: $('#diams-select.card'),
	cardSelectModal: $('#card-select-modal'),
	cardRankSelectList: $('#card-rank-select-list'),
	cardSuitSelectList: $('#card-suit-select-list'),
	currentSeletingCard: null,
	resetCard: $('#reset-card'),
	selectedCards: {
		flop: {
			hearts: [],
			spades: [],
			clubs: [],
			diams: []
		},
		hand: {
			hearts: [],
			spades: [],
			clubs: [],
			diams: []
		}
	},
	results: [],
	resultCard: [null, null],

	init: function(){

		var pThis = this;

		$('#results-back-to-top').hide();

		// Add events
		$('.card-select-option').click(function(event){
			$(pThis.cardRankSelectList).removeClass('invisible');
			pThis.setRanks($(event.target).closest('.card-select-option')[0].classList[3]);
		});

		pThis.resetCard.click(function(){
			pThis.currentSeletingCard.addClass('unspecified-card').removeClass('selecting');
			var insideCard = pThis.currentSeletingCard.find('.card');
			var insideCardClasses = insideCard[0].className.split(' ');

			if (pThis.currentSeletingCard.hasClass('flop-card')){
				var selectIndex = pThis.selectedCards.flop[insideCardClasses[2]].indexOf(insideCardClasses[1]);
				pThis.selectedCards.flop[insideCardClasses[2]].splice(selectIndex, 1);
			} else {
				var selectIndex = pThis.selectedCards.hand[insideCardClasses[2]].indexOf(insideCardClasses[1]);
				pThis.selectedCards.hand[insideCardClasses[2]].splice(selectIndex, 1);
			}

			insideCard.removeClass().addClass('card');
			insideCard.find('.rank').text('?');
			insideCard.find('.suit').html('');
			pThis.closeModal();
		});


		$('.specifiable-card').click(function(event){
			var card = $(event.target).closest('li');
			if (card.hasClass('selecting')){ // if selected card is clicked remove class
				card.removeClass('selecting');
				
				pThis.currentSeletingCard = null;
				pThis.closeModal();
			} else {
				var thisCard = $(this);
				if (!$(this).hasClass('unspecified-card')){
					pThis.resetCard.removeClass('invisible');
				} else {
					pThis.resetCard.addClass('invisible');
				}

				if (pThis.currentSeletingCard){ // if a card was already selected
					pThis.currentSeletingCard.removeClass('selecting'); 
				}

				$(card).addClass('selecting'); // make the newest one the only selected card
				pThis.currentSeletingCard = $(card);
				pThis.openModal();
			}
		});

		$('.selectable').click(function(event){
			var card = $(event.target).closest('.list-group-item')[0];
			pThis.currentSeletingCard.removeClass('selecting');
			var selectableCardClasses = $(card).find('.card')[0].className.split(' ');
			var insideCardClasses = pThis.currentSeletingCard.find('.card')[0].className.split(' ');

			if (pThis.currentSeletingCard.hasClass('flop-card')){
				if(insideCardClasses.length > 1){
					// have to remove previous card from selectedCards list
					var selectIndex = pThis.selectedCards.flop[insideCardClasses[2]].indexOf(insideCardClasses[1]);
					pThis.selectedCards.flop[insideCardClasses[2]].splice(selectIndex, 1);
				}
				pThis.selectedCards.flop[selectableCardClasses[2]].push(selectableCardClasses[1]);
			} else {
				if(insideCardClasses.length > 1){
					// have to remove previous card from selectedCards list
					var selectIndex = pThis.selectedCards.hand[insideCardClasses[2]].indexOf(insideCardClasses[1]);
					pThis.selectedCards.hand[insideCardClasses[2]].splice(selectIndex, 1);
				}
				pThis.selectedCards.hand[selectableCardClasses[2]].push(selectableCardClasses[1]);



				if (pThis.currentSeletingCard[0].id == 'hand1'){
					pThis.resultCard[0] = {card: pThis.bigToMiniClass(selectableCardClasses[2]), rank: 'mini-' + selectableCardClasses[1]};
				} else if (pThis.currentSeletingCard[0].id == 'hand2'){
					pThis.resultCard[1] = {card: pThis.bigToMiniClass(selectableCardClasses[2]), rank: 'mini-' + selectableCardClasses[1]};
				}

				pThis.updateMainResults();

			}

			if (pThis.currentSeletingCard[0].id == 'flop3' || pThis.currentSeletingCard[0].id == 'flop4'){
				pThis.currentSeletingCard.html(card.innerHTML + '<hr class ="line"></hr>');
			} else {
				pThis.currentSeletingCard.html(card.innerHTML);
			}

			pThis.currentSeletingCard.removeClass('unspecified-card');
			pThis.currentSeletingCard = null;
			pThis.closeModal();
		});

		$('#betting-rounds-list').on('click', '.add-action', function(event){
			event.preventDefault();
			var bettingRound = $($(this).closest('.betting-round'));
			var bettingSequenceList = bettingRound.find('.betting-sequence-list');
			bettingSequenceList.find('.betting-round-no-action').remove();
			var numActions = bettingSequenceList.find('.round-bet').length;
			if (numActions < 6) {
				var labelText = (numActions == 0 && bettingRound.index() > 0) ? 'Bet' : 'Raise';
				var betActionHTML = '<div class="betting-round-action round-bet"> ' + 
										'<label class="label label-success">' + labelText + '</label> ' + 
									'</div>';
				
				if (numActions > 0){
					$(bettingSequenceList.find('.round-bet')[numActions - 1]).after(betActionHTML);
				} else if (bettingSequenceList.find('.round-check').length > 0){
					$(bettingSequenceList.find('.round-check')[0]).after(betActionHTML);
				} else if (bettingSequenceList.find('.betting-round-blinds').length > 0){
					$(bettingSequenceList.find('.betting-round-blinds')[0]).after(betActionHTML);
				} else {
					bettingSequenceList.prepend(betActionHTML);
				}

				if ((bettingRound.index() == 0 && numActions >= 2) || numActions >= 3){
					$(this).addClass('disabled');
				}
			}
		});

		$('#betting-rounds-list').on('click', '.remove-action', function(event){
			event.preventDefault();
			var bettingRounds = $('.betting-round');
			var bettingRound = $($(this).closest('.betting-round'));
			var bettingActionList = bettingRound.find('.round-bet');
			var removeCheck = false;

			if (bettingRound.find('.round-call').length > 0 && ((bettingRounds.length - 1) == bettingRound.index())) { // if last round
				bettingRound.find('.round-call').remove(); // remove the call if there is one
			} else {
				bettingActionList.last().remove(); // else remove the last bet
				if (bettingActionList.length == 1 && !(bettingRounds.length - 1 == bettingRound.index()) && (bettingRound.find('.round-check').length == 0)){
					// if there was only one bet (now its 0) and this isnt the last round and there isnt a check, add a check
					// so its not invalid
					$(bettingRound.find('.check-action')).click();
				} else if (bettingActionList.length == 0 && (bettingRounds.length - 1 == bettingRound.index()) && bettingRound.find('.round-check').length > 0){
					// else if this is the last round and there were no bets to remove
					bettingRound.find('.round-check').remove();	
					removeCheck = true;
				}

			}
			if (bettingActionList.length <= 1){ // remove last and add noAction
				if((bettingRound.find('.round-check').length == 0 || removeCheck) && ((bettingRounds.length - 1) == bettingRound.index()) && (bettingRound.index() != 0)){
					var noActionHTML = '<div class="betting-round-no-action">' +
											'<label class="label label-warning">No Action</label>' +
										'</div>';
					bettingRound.find('.betting-sequence-list').html(noActionHTML);
				}
			}
			else if (bettingRound.find('.betting-round-no-action').length == 1 && bettingRounds.length > 1){
				bettingRound.remove();
				$('#add-betting-round').removeClass('disabled');
			}

			if ((bettingRound.index() == 0 && bettingActionList.length < 4) || (bettingRound.index() > 0 && bettingActionList.length < 5)){
				bettingRound.find('.add-action').removeClass('disabled');
			}
			if (bettingRound.find('.round-check').length == 0){
				$(bettingRound.find('.check-action')).removeClass('btn-info');
				$(bettingRound.find('.check-action')).addClass('btn-primary');
			}
		});

		$('#betting-rounds-list').on('click', '.check-action', function(event){
			event.preventDefault();
			var bettingRounds = $('.betting-round');
			var bettingRound = $($(this).closest('.betting-round'));
			var bettingSequenceList = bettingRound.find('.betting-sequence-list');
			var checkText = ((bettingRound.index() == 0) ? 'Call' : 'Check');
			var checkActionHTML = '<div class="betting-round-action round-check"> ' + 
										'<label class="label label-primary">' + checkText + '</label> ' + 
									'</div>';

			bettingSequenceList.find('.betting-round-no-action').remove();
			if ($(this).hasClass('btn-primary')) {

				if (bettingRound.index() == 0){
					$(bettingSequenceList.find('.betting-round-blinds')[0]).after(checkActionHTML);
				} else {
					bettingSequenceList.prepend(checkActionHTML);
				}

				$(this).removeClass('btn-primary').addClass('btn-info');

			} else if (bettingSequenceList.find('.round-bet').length > 0 || (bettingRound.index() == (bettingRounds.length - 1))) {
				bettingSequenceList.find('.round-check').remove();
				$(this).removeClass('btn-info').addClass('btn-primary');
			}

			if (bettingSequenceList.find('.betting-round-action').length == 0 && (bettingRound.index() != 0)){
								var noActionHTML = '<div class="betting-round-no-action">' +
											'<label class="label label-warning">No Action</label>' +
											'</div>';
				bettingSequenceList.html(noActionHTML);
			}
		});

		$('#remove-betting-round').click(function(){

			var bettingRoundsList = $('#betting-rounds-list');
			var bettingRounds = bettingRoundsList.find('.betting-round');

			var flopCards = $('.flop-card');
			flopCards.removeClass('card-greyout');

			$(flopCards[4]).addClass('card-greyout');
			if (bettingRounds.length < 4){
				$(flopCards[3]).addClass('card-greyout');
				if (bettingRounds.length < 3){
					$(flopCards[2]).addClass('card-greyout');
					$(flopCards[1]).addClass('card-greyout');
					$(flopCards[0]).addClass('card-greyout');
				}
			}

			if (bettingRounds.length == 2){
				$(this).addClass('disabled');
			}
			bettingRounds.last().remove();
			
			bettingRoundsList = $('#betting-rounds-list');
			bettingRounds = bettingRoundsList.find('.betting-round');			
			bettingRounds.last().find('.remove-action').click();

			$('#add-betting-round').removeClass('disabled');
		});

		$('#add-betting-round').click(function(){
			var bettingRoundsList = $('#betting-rounds-list');
			var bettingRounds = bettingRoundsList.find('.betting-round');

			var flopCards = $('.flop-card');
			flopCards.addClass('card-greyout');

			$(flopCards[0]).removeClass('card-greyout');
			$(flopCards[1]).removeClass('card-greyout');
			$(flopCards[2]).removeClass('card-greyout');
			if (bettingRounds.length > 1){
				$(flopCards[3]).removeClass('card-greyout');
				if (bettingRounds.length > 2) {
					$(flopCards[4]).removeClass('card-greyout');
				}
			}
			
			var callActionHTML = '<div class="betting-round-action round-call"> ' + 
							'<label class="label label-primary"> </label> ' + 
						'</div>';
			var lastBettingRound = $(bettingRounds[bettingRounds.length - 1]);

			if (lastBettingRound.find('.betting-round-no-action').length > 0 || ((bettingRounds.length == 1) && lastBettingRound.find('.round-bet').length == 0 && lastBettingRound.find('.round-check').length == 0)){
				lastBettingRound.find('.betting-round-no-action').remove();
				lastBettingRound.find('.check-action').click();
			}

			var bettingSequenceList = $(lastBettingRound.find('.betting-sequence-list'));

			if (bettingSequenceList.find('.round-call').length == 0){
				bettingSequenceList.append(callActionHTML);
			}

			$('#remove-betting-round').removeClass('disabled');

			var numRounds = bettingRounds.length;
			var toggleText = (numRounds == 0) ? 'Call' : 'Check';
			if (numRounds < 4) {
				var bettingRoundGuid = pThis.guid();
				var roundHTML = '<li class="betting-round" id="' + bettingRoundGuid + '"> ' + 
									'<div class="betting-sequence-list col-md-10 col-sm-10 col-xs-10"> ' + 
										'<div class="betting-round-no-action">' +
											'<label class="label label-warning">No Action</label>' +
										'</div>' +
									'</div> ' + 
									'<div class="betting-round-action-buttons col-md-2 col-sm-2 col-xs-2">' +
										'<a href="#" class="btn btn-primary check-action" data-toggle="tooltip" data-placement="top" title="Toggle ' + toggleText + '" data-container="body">' +
											'<i class="glyphicon glyphicon-ok"></i>' +
										'</a>' +									
										'<a href="#" class="btn btn-danger remove-action" data-toggle="tooltip" data-placement="top" title="Remove Action">' +
											'<i class="glyphicon glyphicon-minus"></i>' +
										'</a>' +
										'<a href="#" class="btn btn-success add-action" data-toggle="tooltip" data-placement="top" title="Add Bet/Raise">' +
											'<i class="glyphicon glyphicon-plus"></i>' +
										'</a>' +
									'</div>' +
								'</li>';
				bettingRoundsList.append(roundHTML);
				$('a[data-toggle]').tooltip();
				if (numRounds == 3){
					$(this).addClass('disabled');
				}
			}
		});

		$('#query-submit-button').click(function(event){


			$('#query-submit-button').addClass('disabled');
			var popoverContent = '';
			var bettingString = '';
			var specifiedCards = $('.flop-card').not('.unspecified-card').not('.card-greyout');
			var bettingRounds = $('.betting-round');
			switch (specifiedCards.length){

				case 0:
					if (bettingRounds.length > 1){
						popoverContent = 'There can not be more than 1 betting round before the first flop.';
					} else {
						// verifying the betting rounds
						var verifiedObj = pThis.verifyBettingRounds(bettingRounds);
						popoverContent = verifiedObj.error;
						bettingString = verifiedObj.bettingString;
					}
					break;

				case 1:
					popoverContent = 'The betting has reached the second round, so the first three flop cards must be set.'; 
					break; 			

				case 2: 
					popoverContent = 'The betting has reached the second round, so the first three flop cards must be set.'; 
					break; 

				case 3: 
					if (specifiedCards[2].id != 'flop3'){
						popoverContent = 'The betting has reached the second round, so the first three board cards must be set.';
						break;
					} else if (bettingRounds.length != 2) {
						popoverContent = 'The first flop needs exactly 2 betting rounds.';
						break;
					} else {
						// verifying the betting rounds
						var verifiedObj = pThis.verifyBettingRounds(bettingRounds);
						popoverContent = verifiedObj.error;
						bettingString = verifiedObj.bettingString;
					}
					break;

				case 4:
					if (specifiedCards[3].id != 'flop4'){
						popoverContent = 'The betting has reached the third round, so the first four board cards must be set.';
						break;
					} else if (bettingRounds.length != 3){
						popoverContent = 'The second flop needs exactly 3 betting rounds.';
						break;
					} else {
						// verifying the betting rounds
						var verifiedObj = pThis.verifyBettingRounds(bettingRounds);
						popoverContent = verifiedObj.error;
						bettingString = verifiedObj.bettingString;
					}

					break;
				case 5:
					if (bettingRounds.length != 4){
						popoverContent = 'The betting has reached the final round, so all board cards must be set.';
						break;
					} else {
						// verifying the betting rounds
						var verifiedObj = pThis.verifyBettingRounds(bettingRounds);
						popoverContent = verifiedObj.error;
						bettingString = verifiedObj.bettingString;
					}
					break;
			}

			if (popoverContent){

				pThis.submitPopUp(popoverContent);

				event.stopPropagation();
				if (window.event){
					window.event.cancelBubble = true;	
				}
				
				$('#query-submit-button').removeClass('disabled');
			} else {
				// construct card string

				var cardString = pThis.constructCardString(specifiedCards);
				console.log(cardString);
				var query = bettingString + ':' + cardString;
				// the query is good to go
				$(this).addClass('submit-loading');
				pThis.sendQuery(query);
				console.log('query sent', query);
			}
		});

		$('#results-header button').click(function(){
			var direction = -1;
			if ($(this).hasClass('sort-up')){
				$(this).removeClass('sort-up').addClass('sort-down');
			} else if ($(this).hasClass('sort-down')){
				$(this).removeClass('sort-down').addClass('sort-up');
				direction = 1;
			} else {
				var sortButtons = $('#results-header button');
				sortButtons.removeClass('sort-up sort-down');
				$(this).addClass('sort-down');
			}
			pThis.sortResultList($(this).data().sortby, direction);
		});

		$('#results-list').on('click', '.result-row-li', function(){

			pThis.selectedCards.hand =  {
				hearts: [],
				spades: [],
				clubs: [],
				diams: []
			};

			pThis.resultCard = [];

			var htmlFromMini = function(miniCard, handCardNumber){
				var miniCardClass = miniCard.className.split(' ');
				miniCardClass = (miniCardClass[1] != 'mini-card') ? miniCardClass[1] : miniCardClass[0];

				pThis.resultCard.push({rank: 'mini-rank-' + miniCard.innerHTML, card: miniCardClass});	
				console.log(pThis.resultCard[handCardNumber]);

				switch (miniCardClass){
					case 'mini-d': miniCardClass = 'diams';
						break;
					case 'mini-c': miniCardClass = 'clubs'; 
						break;
					case 'mini-h': miniCardClass = 'hearts'; 
						break;
					case 'mini-s': miniCardClass = 'spades';
						break;
				}
				

				miniCardInnerHTML = (miniCard.innerHTML.toLowerCase() == 't') ? '10' : miniCard.innerHTML.toLowerCase();

				pThis.selectedCards.hand[miniCardClass].push('rank-' + miniCardInnerHTML);		

				return '<a href="#" class="card rank-' + miniCardInnerHTML + ' ' + miniCardClass + '"> \
							<span class="rank">' + miniCardInnerHTML.toUpperCase() + '</span> \
							<span class="suit">&' + miniCardClass + ';</span> \
						</a>';
			};

			var resultObj = {
				fold: $(this).data().resultfold,
				call: $(this).data().resultcall,
				raise: $(this).data().resultraise,
				P1Prob: $(this).data().resultp1,
				P2Prob: $(this).data().resultp2
			};

			$('#hand1').removeClass('unspecified-card');
			$('#hand2').removeClass('unspecified-card');


			$('#hand1').html(htmlFromMini($(this).find('.mini-card')[0], 0));
			$('#hand2').html(htmlFromMini($(this).find('.mini-card')[1], 1));

			console.log('pThis.resultCard', pThis.resultCard);

			pThis.generatePie(resultObj);

			$('#main-stats').html('<div class="stat-summary" > \
                <table class="table"> \
                    <tr> \
                        <td class="col-md-6">Player Probability</td> \
                        <td class="col-md-6">' + resultObj.P1Prob + '</td> \
                    </tr> \
                    <tr> \
                        <td class="col-md-6">Opponent Probability</td> \
                        <td class="col-md-6">' + resultObj.P2Prob + '</td> \
                    </tr> \
                    <tr> \
                        <td class="col-md-6">Fold</td> \
                        <td class="col-md-6">' + resultObj.fold + '%</td> \
                    </tr> \
                    <tr> \
                        <td class="col-md-6">Call</td> \
                        <td class="col-md-6">' + resultObj.call + '%</td> \
                    </tr> \
                    <tr> \
                        <td class="col-md-6">Raise</td> \
                        <td class="col-md-6">' + resultObj.raise + '%</td> \
                    </tr> \
                </table> \
            </div> \
            ');
			
		});

		$('[data-toggle]').tooltip();

		$('#results-list').scroll(function() {
			console.log("scrolling");
			if($(this).scrollTop() == 0){
				console.log("Scrolled to the top");
				$('#results-back-to-top').hide();
			} else {
				$('#results-back-to-top').show();
			}
		});

		$('#results-back-to-top').click(function () {
			$(this).hide();
			$('#results-list').animate({ scrollTop: 0 });
		});


	},
	submitPopUp: function(content){
		$('#query-submit-button').attr('data-content', content);

		$('#query-submit-button').popover({
			placement: 'bottom',
			title: 'Oops',
			trigger: 'click',
		}).popover('show');

		setTimeout(function() {
			$('#query-submit-button').popover('destroy');
		}, 3000);		
	},

	sendQuery: function(query){
		var pThis = this;
		console.log('sendQuery:', query);
		
		pThis.previousSort = null;
		var sortButtons = $('.sort-down,.sort-up');
		if (sortButtons.length != 0){
			pThis.previousSort = {
				sortby: sortButtons.data().sortby,
				direction: (sortButtons.hasClass('sort-up')) ? 1 : -1
			};
		}


		$.get('/query', {queryString: query}, function(data) {
			$('#query-submit-button').removeClass('disabled');

			pThis.results = [];
			var rows = data.split('\n');

			if (rows[0].split(' ') == ''){
				pThis.submitPopUp('The query was sent but there was nothing for the strategy to do.');
				return;
			}
			console.log('Number of Rows:', rows[0], 'Actual:', rows.length - 2);

			for (var i = 1; i < rows.length-1; i++) {
				rows[i] = rows[i].split(' ');

				var miniCardRank1 = (rows[i][0][0] == 'T') ? 10 : rows[i][0][0];
				var miniCardRank2 = (rows[i][0][2] == 'T') ? 10 : rows[i][0][2];

				var resultObj = {
					cardindex: i-1,
					cardHTML: '<div class="results-card-pair"><span class="mini-card mini-' + rows[i][0][1] + ' mini-rank-' + miniCardRank1 + '">' + miniCardRank1 + '</span><span class="mini-card mini-' + rows[i][0][3] + ' mini-rank-' + miniCardRank2 + '">' + miniCardRank2 + '</span></div> ',
					fold: (rows[i][1]*100),
					call: (rows[i][2]*100),
					raise: (rows[i][3]*100),
					P1Prob: rows[i][4],
					P2Prob: rows[i][5]
				};

				resultObj.html = pThis.createResultRowHTML(resultObj);

				pThis.results.push(resultObj);
			}

			console.log(pThis.results);
			pThis.setResults();

			pThis.updateMainResults();
			//$('#results-header button').removeClass('sort-down sort-up');
			
			//$('#card-sort').removeClass('sort-down').addClass('sort-up');
			if (!pThis.previousSort){
				$('#p1-sort').click();
			} else {
				pThis.sortResultList(pThis.previousSort.sortby, pThis.previousSort.direction);
			}

		});
	},

	updateMainResults: function(){
		var pThis = this;
		if (pThis.resultCard && pThis.resultCard[0] && pThis.resultCard[1]){

			$('.' + pThis.resultCard[0].card + '.' + pThis.resultCard[0].rank)
				.closest('.results-card-pair')
				.find('.' + pThis.resultCard[1].card + '.' + pThis.resultCard[1].rank).click();
		}
	},

	constructCardString: function(specifiedCards){
		console.log('constructCardString');
		var cardString = '';

		if (specifiedCards.length > 0) {
			for (var i = 0; i < specifiedCards.length; i++) {
				console.log(specifiedCards[i]);
				var innerCardClasses = $(specifiedCards[i]).find('.card')[0].className.split(' ');;
				console.log(innerCardClasses);
				var innerCardRank = '';
				var innerCardSuit = '';
				for (var j = 0; j < innerCardClasses.length; j++){
					var tempClassName = innerCardClasses[j];
					switch (tempClassName.substring(0,4)){
						case 'rank':
							if(tempClassName == "rank-10"){
								innerCardRank = 'T';
							} else {
								innerCardRank = tempClassName.toUpperCase().substring(tempClassName.length-1);
							}
							break;
						case 'card': break;
						default: innerCardSuit = tempClassName.substr(0,1); 
							break;
					}
				}
				cardString += innerCardRank + innerCardSuit;
			}
		}
		return cardString;
	},

	verifyBettingRounds: function(bettingRounds){
		console.log('verifyBettingRounds');
		var error = '';
		var finalBettingString = '';
		for (var i = 0; i < bettingRounds.length; i++){
			var tempBettingString = '';
			var roundActions = $(bettingRounds[i]).find('.betting-round-action');
			for (var j = 0; j < roundActions.length; j++){
				var action = $(roundActions[j]);
				if (action.hasClass('round-bet')){
					tempBettingString += 'r';
				} else {
					tempBettingString += 'c';
				}
			}
			if (bettingRounds.length == 1){
				// only 1 round, special case
				console.log('only round');
				var bettingStringRegex = new RegExp('^c?r{0,3}c?$');
				if (bettingStringRegex.test(tempBettingString)){

					finalBettingString += tempBettingString;
					// if it ends with a call/check, close the round
					if (tempBettingString.length > 1 && tempBettingString.indexOf('c', tempBettingString.length -1) !== -1){
						finalBettingString += '/';
					}
				} else {
					error = 'The first betting round is not valid. \
							There are a max of 3 bets in the first round. \
							Make sure that it follows the form: "call, 0 to 3 bets, call/check".';
				}
			} else if (i == 0){
				// first round, must be complete
				console.log('first round, must be complete');
				var bettingStringRegex = new RegExp('^c?r{0,3}c$');
				console.log(tempBettingString);
				console.log(tempBettingString.length);
				if (bettingStringRegex.test(tempBettingString) && tempBettingString.length > 1){
					finalBettingString += tempBettingString + '/';
				} else {
					error = 'The 1st betting round is not valid. Make sure it ends with a call/check and has at least 2 actions, eg: "bet, call or check, check".';
				}
			} else if (i < bettingRounds.length - 1){
				// is not the last round, check if complete
				console.log('not last round');
				var bettingStringRegex = new RegExp('^c?r{0,4}c$');
				if (bettingStringRegex.test(tempBettingString)){
					finalBettingString += tempBettingString + '/';
				} else {
					error = 'The ' + (i+1) + ((i == 1) ? 'nd' : 'rd') + ' betting row is not valid. Make sure it ends with a "call/check".';
				}

			} else {
				console.log('last round, need not be completed');

				var bettingStringRegex = new RegExp('^c?r{0,4}c?$');
				if (bettingStringRegex.test(tempBettingString)){
					finalBettingString += tempBettingString;
				} else {
					error = 'The last betting row is not valid. Make sure that it follows the form: "call, 0 to 4 bet(s), call/check".';
				}
			}

			if (error != '') break;

		}
		return {bettingString: finalBettingString, error: error};
	},

	openModal: function(){
		var pThis = this;
		this.cardSelectModal.modal('show');
		$('.modal-backdrop').click(function(event){
			$('.selecting').removeClass('selecting');
			pThis.currentSeletingCard = null;
			pThis.closeModal();
		});
	},

	closeModal: function(){
		$(this.cardRankSelectList).addClass('invisible');
		this.cardSelectModal.modal('hide');
	},

	setResults: function(){
		console.log('setResults');

		var pThis = this;
		var list = $('#results-list')[0];
		var listHTML = '';

		for (var i = 0; i < pThis.results.length; i++) {
			listHTML += pThis.results[i].html;
		}
		list.innerHTML = listHTML;

	},

	createResultRowHTML: function(resultObj){

		var diff = ((resultObj.fold + resultObj.call + resultObj.raise) - 100);

		if (diff != 0){
			resultObj.fold = Math.round(resultObj.fold);
			resultObj.call = Math.round(resultObj.call);
			resultObj.raise = Math.round(resultObj.raise);
			diff = (100 - (resultObj.fold + resultObj.call + resultObj.raise)) / 3;
			if (resultObj.fold + resultObj.call + resultObj.raise == 99){
				console.log('here');	
			}
			resultObj.fold += diff, resultObj.call += diff, resultObj.raise += diff;

		}
		return '<li class="result-row-li" \
					data-resultcardindex="' + resultObj.cardindex + '" \
					data-resultfold="' + resultObj.fold + '" \
					data-resultcall="' + resultObj.call + '" \
					data-resultraise="' + resultObj.raise + '" \
					data-resultp1="' + resultObj.P1Prob + '" \
					data-resultp2="' + resultObj.P2Prob + '">' + resultObj.cardHTML + ' \
				    <div class="result-bar"> \
				 		<div class="results-fold" style="width: ' + resultObj.fold + '%">' + Math.round(resultObj.fold) + '</div> \
				 		<div class="results-call" style="width: ' + resultObj.call + '%">' + Math.round(resultObj.call) + '</div> \
				 		<div class="results-bet" style="width: ' + resultObj.raise + '%">' + Math.round(resultObj.raise) + '</div> \
					</div> \
					<div class="results-p1seq" >' + parseFloat(resultObj.P1Prob).toFixed(3) + '</div> \
					<div class="results-p2seq" >' + parseFloat(resultObj.P2Prob).toFixed(3) + '</div> \
		        </li>';
	},

	generatePie: function(resultObj) {
		var canvas = $('#pie-canvas')[0];
		var ctx = canvas.getContext("2d");
		var lastend = 0,
			colors = ['#d43f3a', '#428bca', '#5cb85c'],
			data = [resultObj.fold,resultObj.call,resultObj.raise];
			console.log(data);

		for (var i = 0; i < data.length; i++) {
			ctx.fillStyle = colors[i];
			ctx.beginPath();
			ctx.moveTo(canvas.width/2,canvas.height/2);
			ctx.arc(canvas.width/2,canvas.height/2,canvas.height/2,lastend,lastend+(Math.PI*2*(data[i]/100)),false);
			ctx.lineTo(canvas.width/2,canvas.height/2);
			ctx.fill();
			console.log('lastend', lastend);
			lastend += Math.PI*2*(data[i]/100);
		}

	},

	sortResultList: function(sortBy, direction){
		var pThis = this;
		pThis.results.sort(compare);
		pThis.setResults();

		console.log('sortBy',sortBy,'direction', direction);
		function compare(a, b){
			return (b[sortBy]) < (a[sortBy]) ? direction : -direction;
		}
	},

	setRanks: function(suit){
		this.cardRankSelectList.find('.card').removeClass('diams hearts spades clubs').addClass(suit);
		this.cardRankSelectList.find('.suit').html('&' + suit +';');
		$('.hide-card').removeClass('hide-card');
		this.hideSelectedCards(suit);
	},

	hideSelectedCards: function(suit){
		var selectedCardsOfSuit = this.selectedCards.flop[suit].concat(this.selectedCards.hand[suit]);
		for (var i = 0; i < selectedCardsOfSuit.length; i++){
			$(this.cardRankSelectList.find('.' + selectedCardsOfSuit[i])[0]).addClass('hide-card');
		}
	},
	bigToMiniClass: function(bigClass){
		switch (bigClass){
			case 'diams': return 'mini-d';
			case 'clubs': return 'mini-c';
			case 'hearts': return 'mini-h';
			case 'spades': return 'mini-s';
		}
	},
	guid: (function(){
		  function s4() {
		    return Math.floor((1 + Math.random()) * 0x10000)
		               .toString(16)
		               .substring(1);
		  }
		  return function() {
		    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
		           s4() + '-' + s4() + s4() + s4();
		  };
		})(),
};
window.cepheus.init();

if(!!navigator.userAgent.match(/Trident.*rv\:11\./)){
	// F**Kin IE
	$('html').addClass('ie11');
}
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 12:09 AM
Quote:
Originally Posted by ambientsilence
So how many decision points? I think someone mentioned 400 quads, so a factor of 1000 increase? Doesn't seem too far fetched with improved hardware and perhaps some tweaking of the algorithm. They would be finished before you could get a decent amount of people to start playing the game.
If you sort the cards, and then ignore things that are same by re-labeling suits, there are 1755 different flops. If you publicly burned the cards before any actions, you would need to solve 1755 _independent_ games. Each of the games would be just a tiny bit bigger than HU LHE, because those burned cards mean you wouldn't get quite as much out of that same suit-relabeling in the rest of the game. Maybe 2000 times larger overall, and you don't actually have to solve the whole thing all at once, you can do it in 1755 separate pieces.

Quote:
I think if you're going down this route, you should find a game that's definitely out of reach.
If I haven't gotten that ~2000 number wrong, it's probably not a big enough jump.

But "kill the game" sort of feels like the wrong answer to preventing someone from cheating, especially for competitive play rather than open tables online :/
(not that I have a fantastic solution to offer...)
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 12:11 AM
Quote:
Originally Posted by my_nameaintearl
Here is a some code from a file cepheus.js I haven't really read through it
You're looking at the user interface code on the web page. There's not much poker knowledge to be gained there...
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 12:12 AM
Quote:
Originally Posted by nburch
I'll happily go on record as saying heads-up NLHE 100b won't be solved in anyone's lifetime. Adding more players won't make that problem easier...

It's an interesting question of how small the stacks would need to be. We could certainly solve a 2 chip game. I need more free time :/
First of all, amazing work - both the latest publication and all your contributions to imperfect-information games over the years.

A question about some general stuff. Since it is one of possibly many (possibly infinite) Nash equilibria strategies, we would expect to see different convergence points if you ran the iterations many times. Are there any plans to run it again to see how different the next optimal play is? Obviously this may be a big use of resources for little in the way of scientific interest, but it would be very interesting from a poker perspective. Also, if you were to run the process and generate many different optimal strategies, it would be super interesting to see what the equilibria landscape looks like.

In this post you state HUNLHE won't be solved in our lifetimes. Are you sure about this? I've read somewhere that HUNLHE with 200bb stacks has something like 10^40 decision points. In the past 9 years you stated (and you have a chart which shows) that we have gone from solving order 10^6 games to HULHE at 10^14 states - so roughly increasing the exponent by 1.33 every year. At that rate of progress, I make it 19.5 years to hit 10^40. So I would estimate 20 years, give or take, before HUNLHE is a solved game.

Final question: are you accepting PhD students, and do you take people from a maths/machine learning background with no economics knowledge?
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 12:23 AM
When does the speed of light start coming into play?
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 01:30 AM
Quote:
Originally Posted by David Sklansky
When does the speed of light start coming into play?
Lay off da weed bro
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 02:10 AM
Quote:
Originally Posted by Spy_Lord
A question about some general stuff. Since it is one of possibly many (possibly infinite) Nash equilibria strategies, we would expect to see different convergence points if you ran the iterations many times. Are there any plans to run it again to see how different the next optimal play is? Obviously this may be a big use of resources for little in the way of scientific interest, but it would be very interesting from a poker perspective. Also, if you were to run the process and generate many different optimal strategies, it would be super interesting to see what the equilibria landscape looks like.
Yikes. No plans to run another HU LHE strategy. The project took a special resource request to the body that handles Canadian research computing resources. I don't know how we would write that up in a way that would make them want to give us those resources again for that...

It's an interesting question. We've tried looking at this in smaller games, just to see how variable the strategies are. There are definitely strategies that have different actions in a bunch of places, but looking at a bunch of randomly selected strategies has mostly just resulted in an unusable big list of changes in an even bigger sea of numbers. Even answering the question "how different are these strategies" seems to be hard to do well in a way that satisfies human intuition.

Quote:
In this post you state HUNLHE won't be solved in our lifetimes. Are you sure about this? I've read somewhere that HUNLHE with 200bb stacks has something like 10^40 decision points. In the past 9 years you stated (and you have a chart which shows) that we have gone from solving order 10^6 games to HULHE at 10^14 states - so roughly increasing the exponent by 1.33 every year. At that rate of progress, I make it 19.5 years to hit 10^40. So I would estimate 20 years, give or take, before HUNLHE is a solved game.
"Extrapolation bad!" Or so some people tell me

FullyCompletely lists a bunch of sizes in http://webdocs.cs.ualberta.ca/~games...rt-nl-size.pdf -- if you only care about the sizes, you can find them starting on page 10 for a few different HU NLHE games. You're looking for the one sided canonical, total values. The "Infosets" column tells you how many place you'll need to make a decision, and the "Actions" column tells you how many different numbers you'll need in a strategy.

So, for a 200bb game with 1 chip / 2 chip blinds, a strategy has about 1.8*10^47 values. That's a big table, and I don't see hard drives growing that quickly. That's out.

We now have safe methods for throwing away parts of the strategy, and then recovering them as needed, but they've got a big computation cost. Let's ignore that computation cost (bigger than HU LHE in this case) and split the game in half. Best case, for a balanced binary tree, we use the square root of the original space -- 4.2*10^23 values. Lets say we get the same great compression, and use less than a single bit per value -- about 5 * 10^22 bytes. That's still 10 billion TB. I guess that's a "maybe in my lifetime" amount, but it still leaves looking up an answering being a computation 10 billion times larger than HU LHE. So, that's out.

That leaves something unexpected, but it's a pretty surprising unexpected something. 10^47 is pretty big even for a perfect information game.

Quote:
Final question: are you accepting PhD students, and do you take people from a maths/machine learning background with no economics knowledge?
I'm a PhD student, and this is probably wildly off topic, more appropriate in an email to Mike Bowling.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 02:43 AM
Just out of curiosity, how long would it take to solve 20bb or 25bb deep HUNLHE?
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 03:38 AM
Surely if bet sizing were continuous, there would be a way to converge towards a GTO strategy without considering an infinite amount of bet sizes?
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 04:15 AM
backgammon has been solved for some time now, yet theres still plenty of (big) action to be had

the game (or other games) will not die out as a result of it being solved
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 04:27 AM
to breakeven against a gto bot, doesnt we just have to go to the river everytime and bet allin?
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 04:37 AM
Quote:
Originally Posted by 12may2012
to breakeven against a gto bot, doesnt we just have to go to the river everytime and bet allin?
I think we've just solved NLHE guys, time to quit playing.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 07:30 AM
Quote:
Originally Posted by PLBlow
backgammon has been solved for some time now, yet theres still plenty of (big) action to be had

the game (or other games) will not die out as a result of it being solved
Is there big ONLINE action to be had in backgammon?
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 12:08 PM
People should stop mentioning GTO as it is supposedly refering to a possibly non exploitative strategy. This bot clearly uses the knowledge from past hands to decide how to play future hands, so it has an exploitative strategy.

What they claim here is that this bot applies a perfect exploitative strategy, or set of strategies, that exploits the bet/raise/call/check/fold ranges on every street, neglecting human tells {chat dialog, clicking speed}.

Basically they are claiming that Cepheus is the mathematical Nemesis for HU FLHE.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 01:13 PM
Quote:
Originally Posted by Donkem
People should stop mentioning GTO as it is supposedly refering to a possibly non exploitative strategy. This bot clearly uses the knowledge from past hands to decide how to play future hands, so it has an exploitative strategy.

What they claim here is that this bot applies a perfect exploitative strategy, or set of strategies, that exploits the bet/raise/call/check/fold ranges on every street, neglecting human tells {chat dialog, clicking speed}.

Basically they are claiming that Cepheus is the mathematical Nemesis for HU FLHE.
Yeah, I think you're onto something here.

What would a game theorist know about a game theory optimal strategy right?

Everyone, let's turn our attention to donkem here instead of listening to what these crackpot 'scientists' from the 'university' of 'alberta' have to say
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 01:39 PM
Quote:
Just out of curiosity, how long would it take to solve 20bb or 25bb deep HUNLHE?
With one bet size after the flop (like half pot flop/turn, shove river) - about a week or two on your standard home quad CPU.
If you allow more bet sizes it depends what granularity you want to have. CFR is not really well suited for NL. You can use it to solve games with many bet sizes but you lose a lot of potentially useful information so it's "dumb brute force" approach (nevertheless it's feasible if you have a lot of hardware available).

Quote:
to breakeven against a gto bot, doesnt we just have to go to the river everytime and bet allin?
This is a good question. The thing is that Holdem is similar to rock paper scisors (when this approach work) but not quite the same - in poker there are objectively good and bad plays. Objectively good and bad bluffing hands and objectively good and bad bluff catchers. While your bluff every river approach will often work against a GTO it won't work often enough (because it works often enough with some hands - the ones containing blockers to calling range of your opponent and not often enough with random spews).
There are objectively good betting hands on the flop and objectively good calling hands so getting to the river in the first place without losing a lot of EV is not easy either.

Last edited by punter11235; 01-11-2015 at 01:45 PM.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 01:46 PM
What a great thread. Congrats to team cepheus with this amazing achievement.
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 01:58 PM
Quote:
Make the river bet 3 BB instead of 2 and they have to deal another 20 trillion hands.

Put a preflop flop out where those five cards are dead and they have to deal more than 50 quintillion.
I really like this idea for making holdem more resistant to solving. The thing is a lot of NL based games will fall in coming years (cap HU will be first, all the HU sngs second, then 50-100bb will fall as well, probably not to 0.001BB/hand but even something like 0.1BB/hand makes it unplayable with rake).
If you deal 5 dead cards before every hand and put them face-up on the table, then the searching space again will be way too big to attempt to solve the whole thing (at least for a while)
Computers Conquer Texas Hold'em Poker for First Time Quote
01-11-2015 , 01:58 PM
Going all in on the river against a gto bot is never that bad with a hand that has no showdown value tbh (unless it's spot where gto says to check your entire range, or to a lesser extent- when you should never have a shoving range).

Bluffing with hands with bad card removal can only be a small mistake when you consider how rare the spot is- you have to arrive at some river etc on a specific board run out.

NL holdem is much more complex than limit and I doubt it will ever be strongly solved. People already mentioned an infinite number of GTO lines you can take in limit (although it could just be noise with the limping preflop etc), but I'm pretty confident that there's going to be a crazy amount of GTO betsizing/ranges in NL.

There are just many spots where it seems to me impossible for there to be exactly 1 proper betsizing/range splitting (ofc wet boards prob means many hands will be indifferent, but even something like a dry AAx board in a 3bet pot I'm sure you can have a normal size cbet and a checking range, or you could go for very small cbets with a wide range since you are oop and I don't see how it one can be vastly superior to the other).
Computers Conquer Texas Hold'em Poker for First Time Quote

      
m