Игра (логика компа)
На столе 24 карты.
4 туза, 4 двойки, тройки и так до шестерок. (туз = 1).
Два игрока по очереди берут со стола по одной карте (все карты видны, игрок знает что берет) и складивают их на обчую стопку, накапливая в ней количество очков. Например первий взял туз, второй тройку - в стопке 4 очка.
Загадивается число от 1 до 84 (84 = макс. количество очков). Выигрывает тот кто доберет в стопку загаданую суму. А если кто переберет больше - то он проиграл.
Надо написать прогу которая будет у человека выигривать. (Кстати, если человек знает прикол игры, то он победит, хотя ето от первого хода очень зависит)
Есть игра.
На столе 24 карты.
4 туза, 4 двойки, тройки и так до шестерок. (туз = 1).
Два игрока по очереди берут со стола по одной карте (все карты видны, игрок знает что берет) и складивают их на обчую стопку, накапливая в ней количество очков. Например первий взял туз, второй тройку - в стопке 4 очка.
Загадивается число от 1 до 84 (84 = макс. количество очков). Выигрывает тот кто доберет в стопку загаданую суму. А если кто переберет больше - то он проиграл.
Надо написать прогу которая будет у человека выигривать. (Кстати, если человек знает прикол игры, то он победит, хотя ето от первого хода очень зависит)
Ты хочешь чтобы вместо тебя все написали?
не вижу здесь проблемы
Ты хочешь чтобы вместо тебя все написали?
не вижу здесь проблемы
И я не вижу. Просто мне надо было задачу составить. Вот я и смотрю сложная ли она.
Кода писать не надо. Мне Твою идею послушать интересно. А вообще то я уже сам сделал (но послушать всеравно интересно). И програма должна верняк выигрывать :-). Если Ты такой понятливий то понимаеш что полный перебор будет работать пока Солнце не сгорит :-))).
Если шочеш то можна куски кода друг другу переслать и посмотреть чья прога выиграет.
P.S. А вообще то я етот вопрос повесил потому что он интересный (на мой взгляд), ато надоело в разделах смотреть просьбы о помощи в написании контрольних.
P.S. А вообще то я етот вопрос повесил потому что он интересный (на мой взгляд), ато надоело в разделах смотреть просьбы о помощи в написании контрольних.
Это хорошо - хоть какое-то разнообразие в скучном форуме.Если хочешь можем что-нибудь вместе написать.Насчет изначального вопроса - извини не нравится
Я уже и сам забыл что такео писал :)
Стратегия примерно такая:
Все ситуации на столе однозначно отображаются в ключи масива.
Потом один раз идет проход по масиву и его елементы (ониже ситуацыи на столе) отмечаются как проиграшные или выиграшние. Учитывается досяжность одной игровой ситуации из другой. Проход идет от финальной ситуации к начальной.
Может немного неясно обяснил. Попробую найти дома более детальное описание. Если не пропало вместе со старым винчестером - повешу здесь.
Ет я не спорю. Возможно получится и по какойто формуле пощитать, но не факт что ето будет проще.
ЗЫ. Описание метода найду, просто пока не успел.
По какому принципу нужно сделать ход, если выигрышные ситуации недосягаемы?
По какому принципу нужно сделать ход, если выигрышные ситуации недосягаемы?
Знаете игру где из кучки камней можно забирать 1,2 или 3 камешка. В етой игре очень простая стратегия и если оба игрока ее знают то исход игры очевиден еще до ее начала. Для первого игрока если выиграшная ситуацыя досяжна то он уже победил и второй ничего с етим поделать не сможет. Если выиграшная ситуация недосяжно то ето значит что второй игрок сейчас находится в выиграшной ситуации и остается надеятся только на его ошибку и сразу же перехватить инициативу.
В предложеной мной игре (ето не я ее придумал, просто в книге прочел) дело обстоит также, просто росчет выиграшных позицый немножко сложнее.
Тоесть так. Если вы сделали ход и попали в выиграшную ситуацию, то ваш противник после своего хода попасть тоже в выиграшную ситуацию просто не сможет. Но вы на своем следующем ходе точно сможете попасть в новую выиграшную ситуацию. Выиграшная ситуация должна быть на поле после вашего хода. Если же сейчас ваш ход, но на столе уже выиграшная ситуация, значит вы просто должны сделать случайный ход и надеятся что ваш противник не умеет играть и ошибется. Тоесть после его ошибочного хода ситуация на столе будет не выиграшной и вы сразу же гарантировано сможете на следующем ходе сами попасть на выиграш и уже его не отпускать.
2cheburator. Я думал над вашим постом. Мне бы очень хотелось видеть как вы будете делать ходи математическими решениями без помощи алгоритмов в случае когда на столе уже не будет карт с некоторыми номиналами. Я не утверждаю что ето невозможно, просто хочу увидеть :)
Я составил процедуру, которая работает по твоему алгоритму. Но ее можно обыграть независимо от того, чей первый ход. Проблема в том, что выигрышные ситуации меняются в ходе игры. После твоего хода или хода противника ситуация, которая была для тебя выигрышной, может станет проигрышной. И наоборот.
Быть такого не может :). Если она для тебя выиграшная то так оно и будет до самого конца.
Возможно ми не так понимаем друг друга. Выиграшной я называю ситуацию, в которой противник обречен на проиграш если ты будеш делать все ходы по правильной стратегии.
Смотри. Припустим надо набрать все 84 очка. Тогда выиграшной будет ситуация когда на поле уже нет карт - ето сам конец, дальше ситуации когда на поле 2 карты, 4, 6 и т д. Но ето только частичный случай.
Припустим надо набрать 83. Выиграшная ситуация - на столе туз. Также выиграш на столе что угодно но нет тузов (противник вынуден перебрать). А ситуация когда на столе есть несколько карт и один туз - проиграшная, потому что если противник возьмет туз, то ты уже сделаеш перебор, хотя если противник тупой он может етот туз и не взять и ты можеш победить. Но ситуация с одним тузом всеровно проиграшная, потому что ты можеш выиграть только если противнк тупой, а если умный - проиграеш.
Для определения выигрышных ситуаций я формирую массив с числами Спрага-Грюнди. А как ты определяешь выигрышные ситуации?
Не знаком с такими числами.
У меня так:
1. Изначально выиграшные ситуации те где набрано нужное количество очков и те из которых на следующем ходе произойдет перебор.
2. Для каждой выиграшной ситуации ты перебираеш все ситуации из которой она досяжна (их не больше шести так как карты шести номиналов) и отмечаеш их как проиграшные
3. Дальше ситуации нужно просматривать от более позних к более ранним.
Если из розматриваемой ситуации можно попасть только в проиграшные, то отмечаеш ее как выиграшшную е делаеш для нее действия описаные в п.2, если из розсматриваемой ситуации можно попасть в выиграшную, помечаш разсматриваемую как проиграшную
Я нашел свое краткое описание но оно на украинском. Также есть код на С++. Если хочеш, могу привести. Или сам пока будеш пробовать ?
На твою программу любопытно будет взглянуть. Хотя я почти уверен, что смогу подобрать ходы так, что обыграю ее независимо от того, кто первым ходит. ;)
Вспомнил. Читал об етом в той книге откуда задачу взял.
Твоя ошибка в том что ты считаеш числа от количества очков.
SG(43),(42). Но количество очков на столе не есть игровая ситуация.
У меня все ситуации в масиве и их 6^5. (Шесть в пятой степени).
Шесть номиналов и 5 станов каждого номинала от 0 до 4.
:D Дерзай. Только там интерфейс никакой.
#include <stdlib.h>
int logic(int sum);
int comp(int stan);
int game(int stan, int xid);
const int arrsize = 25*25*25;
const int maxsum = 84;
int arr[arrsize];
int suma = 0;
int kk[6] = {4, 4, 4, 4, 4, 4};
int main () {
int sum;
scanf("%i", &sum);
int xid = logic(sum), stan = arrsize - 1;
// if (xid) stan = game(stan, xid);
while (suma != sum) {
scanf("%i", &xid);
stan = game(stan, xid);
if (suma == sum) { printf("Programer daun\n"); return 1; }
stan = game(stan, comp(stan));
if (suma == sum) { printf("Computer winner\n"); return 1; }
}
}
int logic (int sum) {
int ind, stan, i, s, k, max;
int kkart[6];
if (sum == maxsum) return 0;
else arr[0] = 100;
for (ind = 1; ind < arrsize; ind++) {
stan = ind;
s = 0;
for (i = 0; i < 6; i++) {
kkart = stan % 5;
stan /= 5;
s += kkart * (i+1);
}
s = maxsum - s;
if (s > sum) arr[ind] = 100;
else if (s == sum) arr[ind] = 0;
else {
k = 1; max = 200;
for (i = 0; i < 6; i++) {
if (kkart && arr[ind - k] < max) max = arr[ind - k];
k *= 5;
}
if (max == 200) {printf("Ya daun.\n"); exit(1);}
if (max >= 1) arr[ind] = 0;
else arr[ind] = 1;
}
}
k = 25*125;
for (i = 5; i >= 0; i--) {
if (!arr[arrsize-k-1]) return i+1;
k /= 5;
}
return 0;
}
int game(int stan, int xid) {
int i, k;
for (i = 0, k = 1; i < xid-1; i++) k *= 5;
suma += xid;
kk[xid-1]--;
printf("SUM = %i ", suma);
for (i = 0; i < 6; i++) printf("%i ", kk);
printf("\n\n");
return stan - k;
}
int comp(int stan) {
int k = 25*125, i;
for (i = 5; i >= 0; i--) {
if (!arr[stan-k]) {printf("%i\n", i+1); return i+1;}
k /= 5;
}
i = random(6)+1;
printf("UPS %i\n", i);
return i;
}
Сначала вводиш количество очков, потом делаеш ход - число от 1 до 6. В строчке выскочит количество карт всех номиналов оставшихся на столе и сума уже взятых очков.
Твоя программа в некоторых случаях работает некорректно. Например, если надо набрать 50 очков, попробуй сделать такую последовательность ходов: 1 1 1 1 5 5 5 (после этого программа возьмет карту, которой уже нет на столе). :confused:
Твоя программа в некоторых случаях работает некорректно. Например, если надо набрать 50 очков, попробуй сделать такую последовательность ходов: 1 1 1 1 5 5 5 (после этого программа возьмет карту, которой уже нет на столе). :confused:
Вижу вижу. :(. Сори что так долго. Щас болею.
В етой програме я не делал проверок на действия пользователя и забыл проверить действия компа :) Виноват.
Да, дебагал свой код и пришел в ужас по поводу оформления мной же кода. Не судите строго. Я тогда вообще писал левой ногой :).
Вот исправленый метод хода компутера. Вроде теперь должон коректно ходить
int k = 25*125, i;
for (i = 5; i >= 0; i--) {
[color=red] if (kk)[/color]
if (!arr[stan-k]) {printf("%i\n", i+1); return i+1;}
k /= 5;
}
do {
i = random(6)+1;
[color=red] } while (!kk);[/color]
printf("UPS %i\n", i);
return i;
}
1) Если конечное число делится на 7, то выигрывает второй игрок, просто добирая каждым ходом карту так, чтобы в сумме с последним ходом первого игрока получалось 7 очков.
2) Если конечное число же делится на 7 с остатком, то у первого игрока появляется шанс: первым ходом он должен взять карту с этим остатком, и дальше почивать на лаврах - следовать правилу 1. Но это только при условии, что конечное число меньше 28, в противном случае второй игрок на 4-м круге сможет переломить ситуацию, взяв ту карту, для которой уже не будет пары.
:) Не спорю. Стратегия простая, но отвращения у меня почемуто не вызывает.
Ну вот, ты сам показал что твоя "до отвращения простая стратегия" не верна. А я показал статегию в которой ничего переломить нельзя.
Нет проблем, давай сыграем.
Аську высылаю в PM.
Нет проблем, давай сыграем.
Аську высылаю в PM.
Но ты ведь сам написал что можно переломить ситуацию. :)
Ничего против того что ты написал не имею, но до 28 ето ведь частичный случай.
Поиграть сейчас не получится (уволят если роботать не начну :) ).
Можеш поиграть с моей програмкой. Код + исправления я повешал выше.
Конечно ее можно обиграть если задать меньше 28 очков и играть так как ты предлагаеш. Можно в любом случае обиграть, но после 28 стратегия посложнее будет.
Резюме по игре:
вышеописанным способом второй игрок выигрывает во всех случаях, кроме когда загадано число меньше 28, делящееся на 7 с остатком!
Резюме по игре:
вышеописанным способом второй игрок выигрывает во всех случаях, кроме когда загадано число меньше 28, делящееся на 7 с остатком!
Ну блин. В том то и дело. Чтоб первому выиграть если надо набрать больше 28 он должен играть не так как ты предлагаеш а немножко умнее. Завтра постараюсь переделать свою програмку полутше так чтоб можно было выбирать кто первым ходит и попробуеш поиграть.
В этом случае первый выигрывает только если второй ступит (отклонится от вышеописанного)!
Кто тебе сказал что первый будет первые 4 хода играть по твоей стратегии ? Он сразу начнет ходить по другому а не по дополнению к 7.
Короче, есть готовый екзешник, где программа играет за первого?
Готов протестить его на моей стратегии по всему интервалу N !
Простите за ужас кода, поправлял то что было, поиздевался над и без того страшным интерфейсом и вот что получилось
#include <stdio.h>
#include <stdlib.h>
int logic(int sum);
int comp(int stan);
int game(int stan, int xid);
const int arrsize = 25*25*25;
const int maxsum = 84;
int arr[arrsize];
int suma = 0;
int kk[6] = {4, 4, 4, 4, 4, 4};
int history[6*4];
int hist_index = 0;
void printPole(){
int i, j;
for (i = 0; i < 6; ++i){
for (j = 0; j < kk; ++j)
printf(" %i ", i+1);
printf("\n");
}
}
int inputSum(){
int sum;
do {
clrscr();
printf("Input SUM. (1..84)\n");
scanf("%i", &sum);
} while (sum < 1 || sum > 84);
return sum;
}
int inputFirst() {
clrscr();
printf("1 - User first.\n2 - Computer first.");
int c;
do {
c = getch();
} while (c != '1' && c != '2');
return c - '1';
}
void printHistory() {
printf("\n\nSUM = %i\n(", suma);
int i;
for (i = 0; i < hist_index; ++i)
printf(" %i ", history);
printf(")\n");
}
int inputUserStep() {
clrscr();
printPole();
printHistory();
printf("Input step.\n");
int c, ok = 0;;
do {
c = getch();
if (c >= '1' && c <='6' && kk[c-'1'])
ok = 1;
} while(!ok);
return c - '0';
}
void main () {
int sum = inputSum();
logic(sum);
int first = inputFirst();
int xid, stan = arrsize - 1;
while (suma != sum) {
if (stan != arrsize - 1 || !first) {
xid = inputUserStep();
stan = game(stan, xid);
}
if (suma == sum) { printf("User winner\n"); return; }
if (suma > sum) { printf("Computer winner\n"); return; }
stan = game(stan, comp(stan));
if (suma == sum) { printf("Computer winner\n"); return; }
if (suma > sum) { printf("User winner\n"); return; }
}
}
int logic (int sum) {
int ind, stan, i, s, k, max;
int kkart[6];
if (sum == maxsum) return 0;
else arr[0] = 100;
for (ind = 1; ind < arrsize; ind++) {
stan = ind;
s = 0;
for (i = 0; i < 6; i++) {
kkart = stan % 5;
stan /= 5;
s += kkart * (i+1);
}
s = maxsum - s;
if (s > sum) arr[ind] = 100;
else if (s == sum) arr[ind] = 0;
else {
k = 1; max = 200;
for (i = 0; i < 6; i++) {
if (kkart && arr[ind - k] < max) max = arr[ind - k];
k *= 5;
}
if (max == 200) {printf("Ya daun.\n"); exit(1);}
if (max >= 1) arr[ind] = 0;
else arr[ind] = 1;
}
}
k = 25*125;
for (i = 5; i >= 0; i--) {
if (!arr[arrsize-k-1]) return i+1;
k /= 5;
}
return 0;
}
int game(int stan, int xid) {
history[hist_index++] = xid;
int i, k;
for (i = 0, k = 1; i < xid-1; i++) k *= 5;
suma += xid;
kk[xid-1]--;
printPole();
printHistory();
return stan - k;
}
int comp(int stan) {
int k = 25*125, i;
for (i = 5; i >= 0; i--) {
if (kk)
if (!arr[stan-k]) {printf("%i\n", i+1); return i+1;}
k /= 5;
}
do {
i = random(6)+1;
} while (!kk);
printf("UPS %i\n", i);
return i+1;
}
Возможны ошибки, почти не тастил.
Есть выбор кому первый ход отдать.
Alex_soldier, придется тебе скомпилить, екзешку правилами запрещено вешать. Удачной игры Тебе :)
N=07 (Я-второй): 6 1 - я выиграл!
N=14 (Я-второй): 6 1 6 1 - я выиграл!
N=21 (Я-второй): 6 1 6 1 4 3 - я выиграл!
N=28 (Я-второй): 6 1 6 1 4 3 6 1 - я выиграл!
N=35 (Я-второй): 6 1 6 1 4 3 6 1 6 1 - я выиграл!
N=42 (Я-второй): 6 1 6 1 4 3 6 1 6 1 3 4 - я выиграл!
N=49 (Я-второй): 6 1 6 1 4 3 6 1 6 1 3 4 5 2 - я выиграл!
N=56 (Я-второй): 6 1 6 1 4 3 6 1 6 1 3 4 5 2 3 4 - я выиграл!
N=63 (Я-второй): 6 1 6 1 4 3 6 1 6 1 3 4 5 2 3 4 4 3 - я выиграл!
N=70 (Я-второй): 6 1 6 1 4 3 6 1 6 1 3 4 5 2 3 4 4 3 2 5 - я выиграл!
N=77 (Я-второй): 6 1 6 1 4 3 6 1 6 1 3 4 5 2 3 4 4 3 2 5 2 5 - я выиграл!
N=84 (Я-второй): 6 1 6 1 6 1 6 1 5 2 5 2 5 2 5 2 4 3 4 3 4 3 4 3 - я выиграл!
Половина второй части стратегии:
Единственная возможность порулить первому игроку:
N=01 (Я-первый): 1 - я выиграл!
N=02 (Я-первый): 2 - я выиграл!
N=03 (Я-первый): 3 - я выиграл!
N=04 (Я-первый): 4 - я выиграл!
N=05 (Я-первый): 5 - я выиграл!
N=06 (Я-первый): 6 - я выиграл!
N=08 (Я-первый): 1 6 1 - я выиграл!
N=09 (Я-первый): 2 6 1 - я выиграл!
N=10 (Я-первый): 3 6 1 - я выиграл!
N=11 (Я-первый): 4 6 1 - я выиграл!
N=12 (Я-первый): 5 6 1 - я выиграл!
N=13 (Я-первый): 6 6 1 - я выиграл!
N=15 (Я-первый): 1 6 1 6 1 - я выиграл!
N=16 (Я-первый): 2 6 1 6 1 - я выиграл!
N=17 (Я-первый): 3 6 1 6 1 - я выиграл!
N=18 (Я-первый): 4 6 1 6 1 - я выиграл!
N=19 (Я-первый): 5 6 1 6 1 - я выиграл!
N=20 (Я-первый): 6 6 1 6 1 - я выиграл!
N=22 (Я-первый): 1 6 1 6 1 4 3 - я выиграл!
N=23 (Я-первый): 2 6 1 6 1 4 3 - я выиграл!
N=24 (Я-первый): 3 6 1 6 1 4 3 - я выиграл!
N=25 (Я-первый): 4 6 1 6 1 4 3 - я выиграл!
N=26 (Я-первый): 5 6 1 6 1 4 3 - я выиграл!
N=27 (Я-первый): 6 6 1 6 1 4 3 - я выиграл!
Все, как и планировалось!
N = [29..34, 36..41, 43..48, 50..55, 57..62, 64..69, 71..76, 78..83]
Ты ведь не считаеш что в етих случаях результат случайный ? Какую стратегию для ведущего играка (будь он первый или второй) ты можеш предложить ?
Не обижайся, я не хотел сказать что твоя стратегия совсем неверна, но она подходит только для приведенных тобой примеров. А ето только частичное решение. Для чего делать частичное решение, если есть общее.
Так что вторая половина второй части стратегии срабатывает не всегда - первый игрок владеет инициативой, и успешно противодействует попыткам переломить ситуацию.
Тем не менее, некоторые успехи все же есть и у второго игрока:
N=29 (Я-второй): 6 1 6 1 4 4 6 1 или 6 2 6 1 4 3 6 1 - я выиграл!
N=36 (Я-второй): 6 2 6 1 4 3 6 1 6 1 - я выиграл!
Не знаю, с чем это связано, возможно ошибка в алгоритме программы.
С остальными номерами я еще воюю, пока не нашел способа противодействовать ловушке с отсутствующей картой!
Для уверенности, конечно, надо на бумажке нарисовать. Но извени не сейчас. У меня теперь поночам еротика с дипломом :).
А долго пришлось играть пока ети комбинации нащупал ?
ЗЫ. Я тут подумал и из того что в голове крутится. Для 29 у программы проиграшная ситуация и у тебя очень мало шансов ошибится. Сам подумай тебе нужно один раз взять в паре ходов (комп, ты) не 7 а 8, а в остальных брать по 7. Поскольку есть только 4 пари ходов то возможно что она обречена совсем или у нее анс на твою маловероятную ошибку. Чтоб сказать точно надо самому поиграть с дебагером на дозоре.
Сначала думал, что это особенность ситуации N mod 7 = 1, ан нет!
Сначала думал, что это особенность ситуации N mod 7 = 1, ан нет!
В том что сейчас скажу не уверен, но похоже что ето особенность
N mod 7 = маленькое число (1, 2) при ситуации когда остается много монеток на столе. Тоесть тебе не сложно 3 пары ходов держать по 7 на пару, а в одной взять больше.