make leaderboard table show agent ranking info; add total row info in query api
This commit is contained in:
parent
0cc89a3b55
commit
b7b722761e
|
@ -48,11 +48,12 @@ PAGE_FIELDS = ['elements_every_page', 'page_index']
|
||||||
def _get_page(result, elements_every_page, page_index):
|
def _get_page(result, elements_every_page, page_index):
|
||||||
elements_every_page = int(elements_every_page)
|
elements_every_page = int(elements_every_page)
|
||||||
page_index = int(page_index)
|
page_index = int(page_index)
|
||||||
|
total_row = len(result)
|
||||||
total_page = math.ceil(len(result) / float(elements_every_page))
|
total_page = math.ceil(len(result) / float(elements_every_page))
|
||||||
begin = page_index * elements_every_page
|
begin = page_index * elements_every_page
|
||||||
end = min((page_index+1) * elements_every_page, len(result))
|
end = min((page_index+1) * elements_every_page, len(result))
|
||||||
result = result[begin:end]
|
result = result[begin:end]
|
||||||
return result, total_page
|
return result, total_page, total_row
|
||||||
|
|
||||||
def replay(request):
|
def replay(request):
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
|
@ -70,9 +71,9 @@ def query_game(request):
|
||||||
return HttpResponse(json.dumps({'value': -1, 'info': 'elements_every_page and page_index should be given'}))
|
return HttpResponse(json.dumps({'value': -1, 'info': 'elements_every_page and page_index should be given'}))
|
||||||
filter_dict = {key: request.GET.get(key) for key in dict(request.GET).keys() if key not in PAGE_FIELDS}
|
filter_dict = {key: request.GET.get(key) for key in dict(request.GET).keys() if key not in PAGE_FIELDS}
|
||||||
result = Game.objects.filter(**filter_dict).order_by('index')
|
result = Game.objects.filter(**filter_dict).order_by('index')
|
||||||
result, total_page = _get_page(result, request.GET['elements_every_page'], request.GET['page_index'])
|
result, total_page, total_row = _get_page(result, request.GET['elements_every_page'], request.GET['page_index'])
|
||||||
result = serializers.serialize('json', result, fields=('name', 'index', 'agent0', 'agent1', 'win', 'payoff'))
|
result = serializers.serialize('json', result, fields=('name', 'index', 'agent0', 'agent1', 'win', 'payoff'))
|
||||||
return HttpResponse(json.dumps({'value': 0, 'data': json.loads(result), 'total_page': total_page}))
|
return HttpResponse(json.dumps({'value': 0, 'data': json.loads(result), 'total_page': total_page, 'total_row': total_row}))
|
||||||
|
|
||||||
def query_payoff(request):
|
def query_payoff(request):
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
|
@ -89,8 +90,8 @@ def query_agent_payoff(request):
|
||||||
return HttpResponse(json.dumps({'value': -2, 'info': 'name should be given'}))
|
return HttpResponse(json.dumps({'value': -2, 'info': 'name should be given'}))
|
||||||
result = list(Payoff.objects.filter(name=request.GET['name']).values('agent0').annotate(payoff = Avg('payoff')).order_by('-payoff'))
|
result = list(Payoff.objects.filter(name=request.GET['name']).values('agent0').annotate(payoff = Avg('payoff')).order_by('-payoff'))
|
||||||
print(result)
|
print(result)
|
||||||
result, total_page = _get_page(result, request.GET['elements_every_page'], request.GET['page_index'])
|
result, total_page, total_row = _get_page(result, request.GET['elements_every_page'], request.GET['page_index'])
|
||||||
return HttpResponse(json.dumps({'value': 0, 'data': result, 'total_page': total_page}))
|
return HttpResponse(json.dumps({'value': 0, 'data': result, 'total_page': total_page, 'total_row': total_row}))
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def launch(request):
|
def launch(request):
|
||||||
|
|
|
@ -15,7 +15,7 @@ import LinearProgress from '@material-ui/core/LinearProgress';
|
||||||
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
|
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
|
||||||
import PauseCircleOutlineRoundedIcon from '@material-ui/icons/PauseCircleOutlineRounded';
|
import PauseCircleOutlineRoundedIcon from '@material-ui/icons/PauseCircleOutlineRounded';
|
||||||
import ReplayRoundedIcon from '@material-ui/icons/ReplayRounded';
|
import ReplayRoundedIcon from '@material-ui/icons/ReplayRounded';
|
||||||
import NotInterestedIcon from '@material-ui/icons/NotInterested';
|
// import NotInterestedIcon from '@material-ui/icons/NotInterested';
|
||||||
import SkipNextIcon from '@material-ui/icons/SkipNext';
|
import SkipNextIcon from '@material-ui/icons/SkipNext';
|
||||||
import SkipPreviousIcon from '@material-ui/icons/SkipPrevious';
|
import SkipPreviousIcon from '@material-ui/icons/SkipPrevious';
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||||
|
@ -281,30 +281,30 @@ class DoudizhuGameView extends React.Component {
|
||||||
|
|
||||||
computeProbabilityItem(idx){
|
computeProbabilityItem(idx){
|
||||||
return <span className={"waiting"}>Currently Unavailable...</span>
|
return <span className={"waiting"}>Currently Unavailable...</span>
|
||||||
if(this.state.gameInfo.gameStatus !== "ready" && this.state.gameInfo.turn < this.moveHistory.length){
|
// if(this.state.gameInfo.gameStatus !== "ready" && this.state.gameInfo.turn < this.moveHistory.length){
|
||||||
let style = {};
|
// let style = {};
|
||||||
style["backgroundColor"] = this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `rgba(63, 81, 181, ${this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability})` : "#bdbdbd";
|
// style["backgroundColor"] = this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `rgba(63, 81, 181, ${this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability})` : "#bdbdbd";
|
||||||
return (
|
// return (
|
||||||
<div className={"playing"} style={style}>
|
// <div className={"playing"} style={style}>
|
||||||
<div className="probability-move">
|
// <div className="probability-move">
|
||||||
{this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ?
|
// {this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ?
|
||||||
this.computeSingleLineHand(this.cardStr2Arr(this.moveHistory[this.state.gameInfo.turn].probabilities[idx].move))
|
// this.computeSingleLineHand(this.cardStr2Arr(this.moveHistory[this.state.gameInfo.turn].probabilities[idx].move))
|
||||||
:
|
// :
|
||||||
<NotInterestedIcon fontSize="large" />
|
// <NotInterestedIcon fontSize="large" />
|
||||||
}
|
// }
|
||||||
</div>
|
// </div>
|
||||||
{this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ?
|
// {this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ?
|
||||||
<div className={"non-card"}>
|
// <div className={"non-card"}>
|
||||||
<span>{this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `Probability ${(this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability * 100).toFixed(2)}%` : ""}</span>
|
// <span>{this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `Probability ${(this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability * 100).toFixed(2)}%` : ""}</span>
|
||||||
</div>
|
// </div>
|
||||||
:
|
// :
|
||||||
""
|
// ""
|
||||||
}
|
// }
|
||||||
</div>
|
// </div>
|
||||||
)
|
// )
|
||||||
}else {
|
// }else {
|
||||||
return <span className={"waiting"}>Waiting...</span>
|
// return <span className={"waiting"}>Waiting...</span>
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
go2PrevGameState() {
|
go2PrevGameState() {
|
||||||
|
|
|
@ -34,32 +34,55 @@ const modelList = [
|
||||||
];
|
];
|
||||||
|
|
||||||
function LeaderBoard () {
|
function LeaderBoard () {
|
||||||
|
const initRowsPerPage = 10;
|
||||||
|
const [rowsPerPage, setRowsPerPage] = React.useState(initRowsPerPage);
|
||||||
|
const [page, setPage] = React.useState(0);
|
||||||
|
const [rowsTotal, setRowsTotal] = React.useState(0);
|
||||||
const [rows, setRows] = React.useState([]);
|
const [rows, setRows] = React.useState([]);
|
||||||
|
|
||||||
const { type, name } = qs.parse(window.location.search);
|
const { type, name } = qs.parse(window.location.search);
|
||||||
let requestUrl = `${apiUrl}/tournament/`;
|
let requestUrl = `${apiUrl}/tournament/`;
|
||||||
if (type === 'game') {
|
if (type === 'game') {
|
||||||
requestUrl += `query_game?name=${name}`
|
requestUrl += `query_agent_payoff?name=${name}&elements_every_page=${rowsPerPage}&page_index=${page}`
|
||||||
} else if (type === 'agent') {
|
} else if (type === 'agent') {
|
||||||
requestUrl += `query_game?agent0=${name}`
|
requestUrl += `query_game?agent0=${name}&elements_every_page=${rowsPerPage}&page_index=${page}`
|
||||||
}
|
}
|
||||||
console.log(requestUrl);
|
console.log(requestUrl);
|
||||||
|
|
||||||
|
// todo: detect type change then reset page and page size
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
const res = await axios.get(requestUrl);
|
const res = await axios.get(requestUrl);
|
||||||
console.log('wdnmd', res);
|
console.log(res);
|
||||||
setRows(res.data.map((resRow) => {return createData(resRow);}));
|
if (type === 'game') {
|
||||||
|
setRows(res.data.data.map((resRow, index) => {
|
||||||
|
const rank = rowsPerPage * page + index + 1;
|
||||||
|
return createLeaderBoardData(resRow, rank);
|
||||||
|
}));
|
||||||
|
} else if (type === 'agent') {
|
||||||
|
setRows(res.data.data.map((resRow) => {return createData(resRow);}));
|
||||||
|
}
|
||||||
|
setRowsTotal(res.data.total_row)
|
||||||
}
|
}
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [requestUrl])
|
}, [requestUrl, page, rowsPerPage, type])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<MenuBar gameList={gameList} modelList={modelList} />
|
<MenuBar gameList={gameList} modelList={modelList} />
|
||||||
<div style={{marginLeft: '250px'}}>
|
<div style={{marginLeft: '250px'}}>
|
||||||
<div style={{padding: 20}}>
|
<div style={{padding: 20}}>
|
||||||
<EnhancedTable tableRows={rows} routeInfo={{type, name}}/>
|
<EnhancedTable
|
||||||
|
tableRows={rows}
|
||||||
|
routeInfo={{type, name}}
|
||||||
|
page={page}
|
||||||
|
setPage={(q) => {setPage(q)}}
|
||||||
|
rowsPerPage={rowsPerPage}
|
||||||
|
setRowsPerPage={(q) => {setRowsPerPage(q)}}
|
||||||
|
rowsTotal={rowsTotal}
|
||||||
|
type={type}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -78,7 +101,15 @@ function createData(resData) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const headCells = [
|
function createLeaderBoardData(resData, rank) {
|
||||||
|
return {
|
||||||
|
rank: rank,
|
||||||
|
agent: resData.agent0,
|
||||||
|
payoff: resData.payoff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const agentHeadCells = [
|
||||||
{ id: 'id', numeric: false, disablePadding: false, label: 'ID' },
|
{ id: 'id', numeric: false, disablePadding: false, label: 'ID' },
|
||||||
{ id: 'game', numeric: false, disablePadding: false, label: 'Game' },
|
{ id: 'game', numeric: false, disablePadding: false, label: 'Game' },
|
||||||
{ id: 'agent0', numeric: false, disablePadding: false, label: 'Agent 0' },
|
{ id: 'agent0', numeric: false, disablePadding: false, label: 'Agent 0' },
|
||||||
|
@ -88,6 +119,12 @@ const headCells = [
|
||||||
{ id: 'replay', numeric: false, disablePadding: false, label: 'Replay' }
|
{ id: 'replay', numeric: false, disablePadding: false, label: 'Replay' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const leaderBoardHeadCells = [
|
||||||
|
{ id: 'rank', numeric: false, disablePadding: false, label: 'Rank' },
|
||||||
|
{ id: 'agent', numeric: false, disablePadding: false, label: 'Agent' },
|
||||||
|
{ id: 'payoff', numeric: false, disablePadding: false, label: 'Payoff' }
|
||||||
|
];
|
||||||
|
|
||||||
const StyledTableCell = withStyles((theme) => ({
|
const StyledTableCell = withStyles((theme) => ({
|
||||||
head: {
|
head: {
|
||||||
backgroundColor: '#373538',
|
backgroundColor: '#373538',
|
||||||
|
@ -97,7 +134,8 @@ const StyledTableCell = withStyles((theme) => ({
|
||||||
}
|
}
|
||||||
}))(TableCell);
|
}))(TableCell);
|
||||||
|
|
||||||
function EnhancedTableHead() {
|
function EnhancedTableHead(props) {
|
||||||
|
const {headCells} = props;
|
||||||
return (
|
return (
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
@ -115,11 +153,6 @@ function EnhancedTableHead() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
EnhancedTableHead.propTypes = {
|
|
||||||
classes: PropTypes.object.isRequired,
|
|
||||||
rowCount: PropTypes.number.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
const useToolbarStyles = makeStyles((theme) => ({
|
const useToolbarStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
paddingLeft: theme.spacing(2),
|
paddingLeft: theme.spacing(2),
|
||||||
|
@ -206,33 +239,11 @@ const useStyles = makeStyles((theme) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const EnhancedTable = (props) => {
|
const LeaderBoardTableContent = (props) => {
|
||||||
const initRowsPerPage = 10;
|
const { tableRows, rowsPerPage, page, rowsTotal, headCells } = props;
|
||||||
const { tableRows, routeInfo } = props;
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [rowsPerPage, setRowsPerPage] = React.useState(initRowsPerPage);
|
const emptyRows = rowsPerPage - Math.min(rowsPerPage, rowsTotal - page * rowsPerPage);
|
||||||
const [page, setPage] = React.useState(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setRowsPerPage(initRowsPerPage);
|
|
||||||
setPage(0);
|
|
||||||
}, [tableRows]);
|
|
||||||
|
|
||||||
const handleChangePage = (event, newPage) => {
|
|
||||||
setPage(newPage);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangeRowsPerPage = (event) => {
|
|
||||||
setRowsPerPage(parseInt(event.target.value, 10));
|
|
||||||
setPage(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
const emptyRows = rowsPerPage - Math.min(rowsPerPage, tableRows.length - page * rowsPerPage);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
|
||||||
<Paper className={classes.paper}>
|
|
||||||
<EnhancedTableToolbar routeInfo={routeInfo}/>
|
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table
|
<Table
|
||||||
className={classes.table}
|
className={classes.table}
|
||||||
|
@ -240,14 +251,51 @@ const EnhancedTable = (props) => {
|
||||||
size={'medium'}
|
size={'medium'}
|
||||||
aria-label="enhanced table"
|
aria-label="enhanced table"
|
||||||
>
|
>
|
||||||
<EnhancedTableHead
|
<EnhancedTableHead headCells={headCells}/>
|
||||||
classes={classes}
|
|
||||||
rowCount={tableRows.length}
|
|
||||||
/>
|
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{tableRows
|
{tableRows.map((row, index) => {
|
||||||
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
const labelId = `enhanced-table-checkbox-${index}`;
|
||||||
.map((row, index) => {
|
return (
|
||||||
|
<TableRow
|
||||||
|
hover
|
||||||
|
role="checkbox"
|
||||||
|
tabIndex={-1}
|
||||||
|
key={row.rank}
|
||||||
|
>
|
||||||
|
<TableCell component="th" id={labelId} scope="row">
|
||||||
|
{row.rank}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{row.agent}</TableCell>
|
||||||
|
<TableCell>{row.payoff}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{emptyRows > 0 && (
|
||||||
|
<TableRow style={{ height: 53 * emptyRows }}>
|
||||||
|
<TableCell colSpan={3} />
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const AgentTableContent = (props) => {
|
||||||
|
const { tableRows, rowsPerPage, page, rowsTotal, headCells } = props;
|
||||||
|
const classes = useStyles();
|
||||||
|
const emptyRows = rowsPerPage - Math.min(rowsPerPage, rowsTotal - page * rowsPerPage);
|
||||||
|
return (
|
||||||
|
<TableContainer>
|
||||||
|
<Table
|
||||||
|
className={classes.table}
|
||||||
|
aria-labelledby="tableTitle"
|
||||||
|
size={'medium'}
|
||||||
|
aria-label="enhanced table"
|
||||||
|
>
|
||||||
|
<EnhancedTableHead headCells={headCells}/>
|
||||||
|
<TableBody>
|
||||||
|
{tableRows.map((row, index) => {
|
||||||
const labelId = `enhanced-table-checkbox-${index}`;
|
const labelId = `enhanced-table-checkbox-${index}`;
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<TableRow
|
||||||
|
@ -264,22 +312,52 @@ const EnhancedTable = (props) => {
|
||||||
<TableCell>{row.agent1}</TableCell>
|
<TableCell>{row.agent1}</TableCell>
|
||||||
<TableCell>{row.win}</TableCell>
|
<TableCell>{row.win}</TableCell>
|
||||||
<TableCell>{row.payoff}</TableCell>
|
<TableCell>{row.payoff}</TableCell>
|
||||||
<TableCell><a style={{display: "table-cell"}} href={row.replayUrl} target="_blank"><PlayCircleOutlineIcon style={{verticalAlign: "middle"}}/></a></TableCell>
|
<TableCell><a style={{display: "table-cell"}} href={row.replayUrl} rel="noopener noreferrer" target="_blank"><PlayCircleOutlineIcon style={{verticalAlign: "middle"}}/></a></TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{emptyRows > 0 && (
|
{emptyRows > 0 && (
|
||||||
<TableRow style={{ height: 53 * emptyRows }}>
|
<TableRow style={{ height: 53 * emptyRows }}>
|
||||||
<TableCell colSpan={6} />
|
<TableCell colSpan={7} />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const EnhancedTable = (props) => {
|
||||||
|
|
||||||
|
const { tableRows, routeInfo, rowsPerPage, page, setPage, setRowsPerPage, rowsTotal, type } = props;
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
const handleChangePage = (event, newPage) => {
|
||||||
|
setPage(newPage);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeRowsPerPage = (event) => {
|
||||||
|
setRowsPerPage(parseInt(event.target.value, 10));
|
||||||
|
setPage(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
let tableContent = '';
|
||||||
|
if (type === 'game') {
|
||||||
|
tableContent = <LeaderBoardTableContent headCells={leaderBoardHeadCells} tableRows={tableRows} rowsPerPage={rowsPerPage} page={page} rowsTotal={rowsTotal}/>;
|
||||||
|
} else if (type === 'agent') {
|
||||||
|
tableContent = <AgentTableContent headCells={agentHeadCells} tableRows={tableRows} rowsPerPage={rowsPerPage} page={page} rowsTotal={rowsTotal}/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
<Paper className={classes.paper}>
|
||||||
|
<EnhancedTableToolbar routeInfo={routeInfo}/>
|
||||||
|
{tableContent}
|
||||||
<TablePagination
|
<TablePagination
|
||||||
rowsPerPageOptions={[10, 50, 100]}
|
// todo: remove testing page size option
|
||||||
|
rowsPerPageOptions={[2, 10, 50, 100]}
|
||||||
component="div"
|
component="div"
|
||||||
count={tableRows.length}
|
count={rowsTotal}
|
||||||
rowsPerPage={rowsPerPage}
|
rowsPerPage={rowsPerPage}
|
||||||
page={page}
|
page={page}
|
||||||
onChangePage={handleChangePage}
|
onChangePage={handleChangePage}
|
||||||
|
|
Loading…
Reference in New Issue